mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Updates to migrate off of old library model
This commit is contained in:
		
							parent
							
								
									5d13faef33
								
							
						
					
					
						commit
						159ccd807f
					
				| @ -507,15 +507,13 @@ class LibraryController { | |||||||
|     payload.offset = payload.page * payload.limit |     payload.offset = payload.page * payload.limit | ||||||
| 
 | 
 | ||||||
|     // TODO: Temporary way of handling collapse sub-series. Either remove feature or handle through sql queries
 |     // TODO: Temporary way of handling collapse sub-series. Either remove feature or handle through sql queries
 | ||||||
|     // TODO: Update to new library model
 |  | ||||||
|     const oldLibrary = Database.libraryModel.getOldLibrary(req.library) |  | ||||||
|     const filterByGroup = payload.filterBy?.split('.').shift() |     const filterByGroup = payload.filterBy?.split('.').shift() | ||||||
|     const filterByValue = filterByGroup ? libraryFilters.decode(payload.filterBy.replace(`${filterByGroup}.`, '')) : null |     const filterByValue = filterByGroup ? libraryFilters.decode(payload.filterBy.replace(`${filterByGroup}.`, '')) : null | ||||||
|     if (filterByGroup === 'series' && filterByValue !== 'no-series' && payload.collapseseries) { |     if (filterByGroup === 'series' && filterByValue !== 'no-series' && payload.collapseseries) { | ||||||
|       const seriesId = libraryFilters.decode(payload.filterBy.split('.')[1]) |       const seriesId = libraryFilters.decode(payload.filterBy.split('.')[1]) | ||||||
|       payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.user, oldLibrary) |       payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.user, req.library) | ||||||
|     } else { |     } else { | ||||||
|       const { libraryItems, count } = await Database.libraryItemModel.getByFilterAndSort(oldLibrary, req.user, payload) |       const { libraryItems, count } = await Database.libraryItemModel.getByFilterAndSort(req.library, req.user, payload) | ||||||
|       payload.results = libraryItems |       payload.results = libraryItems | ||||||
|       payload.total = count |       payload.total = count | ||||||
|     } |     } | ||||||
| @ -589,9 +587,6 @@ class LibraryController { | |||||||
|    * @param {Response} res |    * @param {Response} res | ||||||
|    */ |    */ | ||||||
|   async getAllSeriesForLibrary(req, res) { |   async getAllSeriesForLibrary(req, res) { | ||||||
|     // TODO: Update to new library model
 |  | ||||||
|     const oldLibrary = Database.libraryModel.getOldLibrary(req.library) |  | ||||||
| 
 |  | ||||||
|     const include = (req.query.include || '') |     const include = (req.query.include || '') | ||||||
|       .split(',') |       .split(',') | ||||||
|       .map((v) => v.trim().toLowerCase()) |       .map((v) => v.trim().toLowerCase()) | ||||||
| @ -610,7 +605,7 @@ class LibraryController { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const offset = payload.page * payload.limit |     const offset = payload.page * payload.limit | ||||||
|     const { series, count } = await seriesFilters.getFilteredSeries(oldLibrary, req.user, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset) |     const { series, count } = await seriesFilters.getFilteredSeries(req.library, req.user, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset) | ||||||
| 
 | 
 | ||||||
|     payload.total = count |     payload.total = count | ||||||
|     payload.results = series |     payload.results = series | ||||||
| @ -741,14 +736,12 @@ class LibraryController { | |||||||
|    * @param {Response} res |    * @param {Response} res | ||||||
|    */ |    */ | ||||||
|   async getUserPersonalizedShelves(req, res) { |   async getUserPersonalizedShelves(req, res) { | ||||||
|     // TODO: Update to new library model
 |  | ||||||
|     const oldLibrary = Database.libraryModel.getOldLibrary(req.library) |  | ||||||
|     const limitPerShelf = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) || 10 : 10 |     const limitPerShelf = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) || 10 : 10 | ||||||
|     const include = (req.query.include || '') |     const include = (req.query.include || '') | ||||||
|       .split(',') |       .split(',') | ||||||
|       .map((v) => v.trim().toLowerCase()) |       .map((v) => v.trim().toLowerCase()) | ||||||
|       .filter((v) => !!v) |       .filter((v) => !!v) | ||||||
|     const shelves = await Database.libraryItemModel.getPersonalizedShelves(oldLibrary, req.user, include, limitPerShelf) |     const shelves = await Database.libraryItemModel.getPersonalizedShelves(req.library, req.user, include, limitPerShelf) | ||||||
|     res.json(shelves) |     res.json(shelves) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -1098,8 +1091,7 @@ class LibraryController { | |||||||
|     if (req.library.mediaType !== 'podcast') { |     if (req.library.mediaType !== 'podcast') { | ||||||
|       return res.sendStatus(404) |       return res.sendStatus(404) | ||||||
|     } |     } | ||||||
|     // TODO: Update to new library model
 | 
 | ||||||
|     const oldLibrary = Database.libraryModel.getOldLibrary(req.library) |  | ||||||
|     const payload = { |     const payload = { | ||||||
|       episodes: [], |       episodes: [], | ||||||
|       limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0, |       limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0, | ||||||
| @ -1107,7 +1099,7 @@ class LibraryController { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const offset = payload.page * payload.limit |     const offset = payload.page * payload.limit | ||||||
|     payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.user, oldLibrary, payload.limit, offset) |     payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.user, req.library, payload.limit, offset) | ||||||
|     res.json(payload) |     res.json(payload) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -44,11 +44,11 @@ class MiscController { | |||||||
|     const files = Object.values(req.files) |     const files = Object.values(req.files) | ||||||
|     const { title, author, series, folder: folderId, library: libraryId } = req.body |     const { title, author, series, folder: folderId, library: libraryId } = req.body | ||||||
| 
 | 
 | ||||||
|     const library = await Database.libraryModel.getOldById(libraryId) |     const library = await Database.libraryModel.findByPk(libraryId) | ||||||
|     if (!library) { |     if (!library) { | ||||||
|       return res.status(404).send(`Library not found with id ${libraryId}`) |       return res.status(404).send(`Library not found with id ${libraryId}`) | ||||||
|     } |     } | ||||||
|     const folder = library.folders.find((fold) => fold.id === folderId) |     const folder = library.libraryFolders.find((fold) => fold.id === folderId) | ||||||
|     if (!folder) { |     if (!folder) { | ||||||
|       return res.status(404).send(`Folder not found with id ${folderId} in library ${library.name}`) |       return res.status(404).send(`Folder not found with id ${folderId} in library ${library.name}`) | ||||||
|     } |     } | ||||||
| @ -63,7 +63,7 @@ class MiscController { | |||||||
|     // before sanitizing all the directory parts to remove illegal chars and finally prepending
 |     // before sanitizing all the directory parts to remove illegal chars and finally prepending
 | ||||||
|     // the base folder path
 |     // the base folder path
 | ||||||
|     const cleanedOutputDirectoryParts = outputDirectoryParts.filter(Boolean).map((part) => sanitizeFilename(part)) |     const cleanedOutputDirectoryParts = outputDirectoryParts.filter(Boolean).map((part) => sanitizeFilename(part)) | ||||||
|     const outputDirectory = Path.join(...[folder.fullPath, ...cleanedOutputDirectoryParts]) |     const outputDirectory = Path.join(...[folder.path, ...cleanedOutputDirectoryParts]) | ||||||
| 
 | 
 | ||||||
|     await fs.ensureDir(outputDirectory) |     await fs.ensureDir(outputDirectory) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,13 +38,13 @@ class PodcastController { | |||||||
|     } |     } | ||||||
|     const payload = req.body |     const payload = req.body | ||||||
| 
 | 
 | ||||||
|     const library = await Database.libraryModel.getOldById(payload.libraryId) |     const library = await Database.libraryModel.findByPk(payload.libraryId) | ||||||
|     if (!library) { |     if (!library) { | ||||||
|       Logger.error(`[PodcastController] Create: Library not found "${payload.libraryId}"`) |       Logger.error(`[PodcastController] Create: Library not found "${payload.libraryId}"`) | ||||||
|       return res.status(404).send('Library not found') |       return res.status(404).send('Library not found') | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const folder = library.folders.find((fold) => fold.id === payload.folderId) |     const folder = library.libraryFolders.find((fold) => fold.id === payload.folderId) | ||||||
|     if (!folder) { |     if (!folder) { | ||||||
|       Logger.error(`[PodcastController] Create: Folder not found "${payload.folderId}"`) |       Logger.error(`[PodcastController] Create: Folder not found "${payload.folderId}"`) | ||||||
|       return res.status(404).send('Folder not found') |       return res.status(404).send('Folder not found') | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ class NotificationManager { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Logger.debug(`[NotificationManager] onPodcastEpisodeDownloaded: Episode "${episode.title}" for podcast ${libraryItem.media.metadata.title}`) |     Logger.debug(`[NotificationManager] onPodcastEpisodeDownloaded: Episode "${episode.title}" for podcast ${libraryItem.media.metadata.title}`) | ||||||
|     const library = await Database.libraryModel.getOldById(libraryItem.libraryId) |     const library = await Database.libraryModel.findByPk(libraryItem.libraryId) | ||||||
|     const eventData = { |     const eventData = { | ||||||
|       libraryItemId: libraryItem.id, |       libraryItemId: libraryItem.id, | ||||||
|       libraryId: libraryItem.libraryId, |       libraryId: libraryItem.libraryId, | ||||||
|  | |||||||
| @ -11,8 +11,6 @@ const LibraryFile = require('../objects/files/LibraryFile') | |||||||
| const Book = require('./Book') | const Book = require('./Book') | ||||||
| const Podcast = require('./Podcast') | const Podcast = require('./Podcast') | ||||||
| 
 | 
 | ||||||
| const ShareManager = require('../managers/ShareManager') |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * @typedef LibraryFileObject |  * @typedef LibraryFileObject | ||||||
|  * @property {string} ino |  * @property {string} ino | ||||||
| @ -559,14 +557,14 @@ class LibraryItem extends Model { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get library items using filter and sort |    * Get library items using filter and sort | ||||||
|    * @param {oldLibrary} library |    * @param {import('./Library')} library | ||||||
|    * @param {import('./User')} user |    * @param {import('./User')} user | ||||||
|    * @param {object} options |    * @param {object} options | ||||||
|    * @returns {{ libraryItems:oldLibraryItem[], count:number }} |    * @returns {{ libraryItems:oldLibraryItem[], count:number }} | ||||||
|    */ |    */ | ||||||
|   static async getByFilterAndSort(library, user, options) { |   static async getByFilterAndSort(library, user, options) { | ||||||
|     let start = Date.now() |     let start = Date.now() | ||||||
|     const { libraryItems, count } = await libraryFilters.getFilteredLibraryItems(library, user, options) |     const { libraryItems, count } = await libraryFilters.getFilteredLibraryItems(library.id, user, options) | ||||||
|     Logger.debug(`Loaded ${libraryItems.length} of ${count} items for libary page in ${((Date.now() - start) / 1000).toFixed(2)}s`) |     Logger.debug(`Loaded ${libraryItems.length} of ${count} items for libary page in ${((Date.now() - start) / 1000).toFixed(2)}s`) | ||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
| @ -602,7 +600,7 @@ class LibraryItem extends Model { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get home page data personalized shelves |    * Get home page data personalized shelves | ||||||
|    * @param {oldLibrary} library |    * @param {import('./Library')} library | ||||||
|    * @param {import('./User')} user |    * @param {import('./User')} user | ||||||
|    * @param {string[]} include |    * @param {string[]} include | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ class LibraryScanner { | |||||||
|    * @returns {boolean} |    * @returns {boolean} | ||||||
|    */ |    */ | ||||||
|   isLibraryScanning(libraryId) { |   isLibraryScanning(libraryId) { | ||||||
|     return this.librariesScanning.some(ls => ls.id === libraryId) |     return this.librariesScanning.some((ls) => ls.id === libraryId) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
| @ -38,7 +38,7 @@ class LibraryScanner { | |||||||
|    * @param {string} libraryId |    * @param {string} libraryId | ||||||
|    */ |    */ | ||||||
|   setCancelLibraryScan(libraryId) { |   setCancelLibraryScan(libraryId) { | ||||||
|     const libraryScanning = this.librariesScanning.find(ls => ls.id === libraryId) |     const libraryScanning = this.librariesScanning.find((ls) => ls.id === libraryId) | ||||||
|     if (!libraryScanning) return |     if (!libraryScanning) return | ||||||
|     this.cancelLibraryScan[libraryId] = true |     this.cancelLibraryScan[libraryId] = true | ||||||
|   } |   } | ||||||
| @ -89,7 +89,7 @@ class LibraryScanner { | |||||||
|     libraryScan.setComplete() |     libraryScan.setComplete() | ||||||
| 
 | 
 | ||||||
|     Logger.info(`[LibraryScanner] Library scan ${libraryScan.id} completed in ${libraryScan.elapsedTimestamp} | ${libraryScan.resultStats}`) |     Logger.info(`[LibraryScanner] Library scan ${libraryScan.id} completed in ${libraryScan.elapsedTimestamp} | ${libraryScan.resultStats}`) | ||||||
|     this.librariesScanning = this.librariesScanning.filter(ls => ls.id !== library.id) |     this.librariesScanning = this.librariesScanning.filter((ls) => ls.id !== library.id) | ||||||
| 
 | 
 | ||||||
|     if (canceled && !libraryScan.totalResults) { |     if (canceled && !libraryScan.totalResults) { | ||||||
|       task.setFinished('Scan canceled') |       task.setFinished('Scan canceled') | ||||||
| @ -151,14 +151,10 @@ class LibraryScanner { | |||||||
|     let oldLibraryItemsUpdated = [] |     let oldLibraryItemsUpdated = [] | ||||||
|     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) | ||||||
|       if (!libraryItemData) { |       if (!libraryItemData) { | ||||||
|         // Fallback to finding matching library item with matching inode value
 |         // Fallback to finding matching library item with matching inode value
 | ||||||
|         libraryItemData = libraryItemDataFound.find(lid => |         libraryItemData = libraryItemDataFound.find((lid) => ItemToItemInoMatch(lid, existingLibraryItem) || ItemToFileInoMatch(lid, existingLibraryItem) || ItemToFileInoMatch(existingLibraryItem, lid)) | ||||||
|           ItemToItemInoMatch(lid, existingLibraryItem) || |  | ||||||
|           ItemToFileInoMatch(lid, existingLibraryItem) || |  | ||||||
|           ItemToFileInoMatch(existingLibraryItem, lid) |  | ||||||
|         ) |  | ||||||
|         if (libraryItemData) { |         if (libraryItemData) { | ||||||
|           libraryScan.addLog(LogLevel.INFO, `Library item with path "${existingLibraryItem.path}" was not found, but library item inode "${existingLibraryItem.ino}" was found at path "${libraryItemData.path}"`) |           libraryScan.addLog(LogLevel.INFO, `Library item with path "${existingLibraryItem.path}" was not found, but library item inode "${existingLibraryItem.ino}" was found at path "${libraryItemData.path}"`) | ||||||
|         } |         } | ||||||
| @ -166,7 +162,7 @@ class LibraryScanner { | |||||||
| 
 | 
 | ||||||
|       if (!libraryItemData) { |       if (!libraryItemData) { | ||||||
|         // Podcast folder can have no episodes and still be valid
 |         // Podcast folder can have no episodes and still be valid
 | ||||||
|         if (libraryScan.libraryMediaType === 'podcast' && await fs.pathExists(existingLibraryItem.path)) { |         if (libraryScan.libraryMediaType === 'podcast' && (await fs.pathExists(existingLibraryItem.path))) { | ||||||
|           libraryScan.addLog(LogLevel.INFO, `Library item "${existingLibraryItem.relPath}" folder exists but has no episodes`) |           libraryScan.addLog(LogLevel.INFO, `Library item "${existingLibraryItem.relPath}" folder exists but has no episodes`) | ||||||
|         } else { |         } else { | ||||||
|           libraryScan.addLog(LogLevel.WARN, `Library Item "${existingLibraryItem.path}" (inode: ${existingLibraryItem.ino}) is missing`) |           libraryScan.addLog(LogLevel.WARN, `Library Item "${existingLibraryItem.path}" (inode: ${existingLibraryItem.ino}) is missing`) | ||||||
| @ -184,7 +180,7 @@ class LibraryScanner { | |||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } else { |       } else { | ||||||
|         libraryItemDataFound = libraryItemDataFound.filter(lidf => lidf !== libraryItemData) |         libraryItemDataFound = libraryItemDataFound.filter((lidf) => lidf !== libraryItemData) | ||||||
|         let libraryItemDataUpdated = await libraryItemData.checkLibraryItemData(existingLibraryItem, libraryScan) |         let libraryItemDataUpdated = await libraryItemData.checkLibraryItemData(existingLibraryItem, libraryScan) | ||||||
|         if (libraryItemDataUpdated || forceRescan) { |         if (libraryItemDataUpdated || forceRescan) { | ||||||
|           if (forceRescan || libraryItemData.hasLibraryFileChanges || libraryItemData.hasPathChange) { |           if (forceRescan || libraryItemData.hasLibraryFileChanges || libraryItemData.hasPathChange) { | ||||||
| @ -210,7 +206,10 @@ 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 (oldLibraryItemsUpdated.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('items_updated', oldLibraryItemsUpdated.map(li => li.toJSONExpanded())) |         SocketAuthority.emitter( | ||||||
|  |           'items_updated', | ||||||
|  |           oldLibraryItemsUpdated.map((li) => li.toJSONExpanded()) | ||||||
|  |         ) | ||||||
|         oldLibraryItemsUpdated = [] |         oldLibraryItemsUpdated = [] | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
| @ -219,7 +218,10 @@ class LibraryScanner { | |||||||
|     // Emit item updates to client
 |     // Emit item updates to client
 | ||||||
|     if (oldLibraryItemsUpdated.length) { |     if (oldLibraryItemsUpdated.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('items_updated', oldLibraryItemsUpdated.map(li => li.toJSONExpanded())) |       SocketAuthority.emitter( | ||||||
|  |         'items_updated', | ||||||
|  |         oldLibraryItemsUpdated.map((li) => li.toJSONExpanded()) | ||||||
|  |       ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Authors and series that were removed from books should be removed if they are now empty
 |     // Authors and series that were removed from books should be removed if they are now empty
 | ||||||
| @ -228,15 +230,18 @@ class LibraryScanner { | |||||||
|     // Update missing library items
 |     // Update missing library items
 | ||||||
|     if (libraryItemIdsMissing.length) { |     if (libraryItemIdsMissing.length) { | ||||||
|       libraryScan.addLog(LogLevel.INFO, `Updating ${libraryItemIdsMissing.length} library items missing`) |       libraryScan.addLog(LogLevel.INFO, `Updating ${libraryItemIdsMissing.length} library items missing`) | ||||||
|       await Database.libraryItemModel.update({ |       await Database.libraryItemModel.update( | ||||||
|  |         { | ||||||
|           isMissing: true, |           isMissing: true, | ||||||
|           lastScan: Date.now(), |           lastScan: Date.now(), | ||||||
|           lastScanVersion: packageJson.version |           lastScanVersion: packageJson.version | ||||||
|       }, { |         }, | ||||||
|  |         { | ||||||
|           where: { |           where: { | ||||||
|             id: libraryItemIdsMissing |             id: libraryItemIdsMissing | ||||||
|           } |           } | ||||||
|       }) |         } | ||||||
|  |       ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (this.cancelLibraryScan[libraryScan.libraryId]) return true |     if (this.cancelLibraryScan[libraryScan.libraryId]) return true | ||||||
| @ -256,7 +261,10 @@ class LibraryScanner { | |||||||
|         // Emit new items in chunks of 10 to client
 |         // Emit new items in chunks of 10 to client
 | ||||||
|         if (newOldLibraryItems.length === 10) { |         if (newOldLibraryItems.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('items_added', newOldLibraryItems.map(li => li.toJSONExpanded())) |           SocketAuthority.emitter( | ||||||
|  |             'items_added', | ||||||
|  |             newOldLibraryItems.map((li) => li.toJSONExpanded()) | ||||||
|  |           ) | ||||||
|           newOldLibraryItems = [] |           newOldLibraryItems = [] | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -265,7 +273,10 @@ class LibraryScanner { | |||||||
|       // Emit new items to client
 |       // Emit new items to client
 | ||||||
|       if (newOldLibraryItems.length) { |       if (newOldLibraryItems.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('items_added', newOldLibraryItems.map(li => li.toJSONExpanded())) |         SocketAuthority.emitter( | ||||||
|  |           'items_added', | ||||||
|  |           newOldLibraryItems.map((li) => li.toJSONExpanded()) | ||||||
|  |         ) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -321,7 +332,8 @@ class LibraryScanner { | |||||||
|         continue |         continue | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       items.push(new LibraryItemScanData({ |       items.push( | ||||||
|  |         new LibraryItemScanData({ | ||||||
|           libraryFolderId: folder.id, |           libraryFolderId: folder.id, | ||||||
|           libraryId: folder.libraryId, |           libraryId: folder.libraryId, | ||||||
|           mediaType: library.mediaType, |           mediaType: library.mediaType, | ||||||
| @ -334,7 +346,8 @@ class LibraryScanner { | |||||||
|           isFile, |           isFile, | ||||||
|           mediaMetadata: libraryItemData.mediaMetadata || null, |           mediaMetadata: libraryItemData.mediaMetadata || null, | ||||||
|           libraryFiles: fileObjs |           libraryFiles: fileObjs | ||||||
|       })) |         }) | ||||||
|  |       ) | ||||||
|     } |     } | ||||||
|     return items |     return items | ||||||
|   } |   } | ||||||
| @ -366,7 +379,7 @@ class LibraryScanner { | |||||||
| 
 | 
 | ||||||
|     for (const folderId in folderGroups) { |     for (const folderId in folderGroups) { | ||||||
|       const libraryId = folderGroups[folderId].libraryId |       const libraryId = folderGroups[folderId].libraryId | ||||||
|       // const library = await Database.libraryModel.getOldById(libraryId)
 | 
 | ||||||
|       const library = await Database.libraryModel.findByPk(libraryId, { |       const library = await Database.libraryModel.findByPk(libraryId, { | ||||||
|         include: { |         include: { | ||||||
|           model: Database.libraryFolderModel, |           model: Database.libraryFolderModel, | ||||||
| @ -381,7 +394,7 @@ class LibraryScanner { | |||||||
|       } |       } | ||||||
|       const folder = library.libraryFolders[0] |       const folder = library.libraryFolders[0] | ||||||
| 
 | 
 | ||||||
|       const relFilePaths = folderGroups[folderId].fileUpdates.map(fileUpdate => fileUpdate.relPath) |       const relFilePaths = folderGroups[folderId].fileUpdates.map((fileUpdate) => fileUpdate.relPath) | ||||||
|       const fileUpdateGroup = scanUtils.groupFilesIntoLibraryItemPaths(library.mediaType, relFilePaths) |       const fileUpdateGroup = scanUtils.groupFilesIntoLibraryItemPaths(library.mediaType, relFilePaths) | ||||||
| 
 | 
 | ||||||
|       if (!Object.keys(fileUpdateGroup).length) { |       if (!Object.keys(fileUpdateGroup).length) { | ||||||
| @ -471,7 +484,7 @@ class LibraryScanner { | |||||||
|     for (const itemDir in updateGroup) { |     for (const itemDir in updateGroup) { | ||||||
|       if (isSingleMediaFile(fileUpdateGroup, itemDir)) continue // Media in root path
 |       if (isSingleMediaFile(fileUpdateGroup, itemDir)) continue // Media in root path
 | ||||||
| 
 | 
 | ||||||
|       const itemDirNestedFiles = fileUpdateGroup[itemDir].filter(b => b.includes('/')) |       const itemDirNestedFiles = fileUpdateGroup[itemDir].filter((b) => b.includes('/')) | ||||||
|       if (!itemDirNestedFiles.length) continue |       if (!itemDirNestedFiles.length) continue | ||||||
| 
 | 
 | ||||||
|       const firstNest = itemDirNestedFiles[0].split('/').shift() |       const firstNest = itemDirNestedFiles[0].split('/').shift() | ||||||
| @ -523,7 +536,15 @@ class LibraryScanner { | |||||||
| 
 | 
 | ||||||
|       const potentialChildDirs = [fullPath] |       const potentialChildDirs = [fullPath] | ||||||
|       for (let i = 0; i < itemDirParts.length; i++) { |       for (let i = 0; i < itemDirParts.length; i++) { | ||||||
|         potentialChildDirs.push(Path.posix.join(fileUtils.filePathToPOSIX(folder.path), itemDir.split('/').slice(0, -1 - i).join('/'))) |         potentialChildDirs.push( | ||||||
|  |           Path.posix.join( | ||||||
|  |             fileUtils.filePathToPOSIX(folder.path), | ||||||
|  |             itemDir | ||||||
|  |               .split('/') | ||||||
|  |               .slice(0, -1 - i) | ||||||
|  |               .join('/') | ||||||
|  |           ) | ||||||
|  |         ) | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       // Check if book dir group is already an item
 |       // Check if book dir group is already an item
 | ||||||
| @ -535,10 +556,7 @@ class LibraryScanner { | |||||||
|       let updatedLibraryItemDetails = {} |       let updatedLibraryItemDetails = {} | ||||||
|       if (!existingLibraryItem) { |       if (!existingLibraryItem) { | ||||||
|         const isSingleMedia = isSingleMediaFile(fileUpdateGroup, itemDir) |         const isSingleMedia = isSingleMediaFile(fileUpdateGroup, itemDir) | ||||||
|         existingLibraryItem = |         existingLibraryItem = (await findLibraryItemByItemToItemInoMatch(library.id, fullPath)) || (await findLibraryItemByItemToFileInoMatch(library.id, fullPath, isSingleMedia)) || (await findLibraryItemByFileToItemInoMatch(library.id, fullPath, isSingleMedia, fileUpdateGroup[itemDir])) | ||||||
|           await findLibraryItemByItemToItemInoMatch(library.id, fullPath) || |  | ||||||
|           await findLibraryItemByItemToFileInoMatch(library.id, fullPath, isSingleMedia) || |  | ||||||
|           await findLibraryItemByFileToItemInoMatch(library.id, fullPath, isSingleMedia, fileUpdateGroup[itemDir]) |  | ||||||
|         if (existingLibraryItem) { |         if (existingLibraryItem) { | ||||||
|           // Update library item paths for scan
 |           // Update library item paths for scan
 | ||||||
|           existingLibraryItem.path = fullPath |           existingLibraryItem.path = fullPath | ||||||
| @ -603,7 +621,7 @@ class LibraryScanner { | |||||||
| module.exports = new LibraryScanner() | module.exports = new LibraryScanner() | ||||||
| 
 | 
 | ||||||
| function ItemToFileInoMatch(libraryItem1, libraryItem2) { | function ItemToFileInoMatch(libraryItem1, libraryItem2) { | ||||||
|   return libraryItem1.isFile && libraryItem2.libraryFiles.some(lf => lf.ino === libraryItem1.ino) |   return libraryItem1.isFile && libraryItem2.libraryFiles.some((lf) => lf.ino === libraryItem1.ino) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function ItemToItemInoMatch(libraryItem1, libraryItem2) { | function ItemToItemInoMatch(libraryItem1, libraryItem2) { | ||||||
| @ -611,9 +629,7 @@ function ItemToItemInoMatch(libraryItem1, libraryItem2) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function hasAudioFiles(fileUpdateGroup, itemDir) { | function hasAudioFiles(fileUpdateGroup, itemDir) { | ||||||
|   return isSingleMediaFile(fileUpdateGroup, itemDir) ? |   return isSingleMediaFile(fileUpdateGroup, itemDir) ? scanUtils.checkFilepathIsAudioFile(fileUpdateGroup[itemDir]) : fileUpdateGroup[itemDir].some(scanUtils.checkFilepathIsAudioFile) | ||||||
|     scanUtils.checkFilepathIsAudioFile(fileUpdateGroup[itemDir]) : |  | ||||||
|     fileUpdateGroup[itemDir].some(scanUtils.checkFilepathIsAudioFile) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function isSingleMediaFile(fileUpdateGroup, itemDir) { | function isSingleMediaFile(fileUpdateGroup, itemDir) { | ||||||
| @ -627,8 +643,7 @@ async function findLibraryItemByItemToItemInoMatch(libraryId, fullPath) { | |||||||
|     libraryId: libraryId, |     libraryId: libraryId, | ||||||
|     ino: ino |     ino: ino | ||||||
|   }) |   }) | ||||||
|   if (existingLibraryItem) |   if (existingLibraryItem) Logger.debug(`[LibraryScanner] Found library item with matching inode "${ino}" at path "${existingLibraryItem.path}"`) | ||||||
|     Logger.debug(`[LibraryScanner] Found library item with matching inode "${ino}" at path "${existingLibraryItem.path}"`) |  | ||||||
|   return existingLibraryItem |   return existingLibraryItem | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -637,18 +652,20 @@ async function findLibraryItemByItemToFileInoMatch(libraryId, fullPath, isSingle | |||||||
|   // check if it was moved from another folder by comparing the ino to the library files
 |   // check if it was moved from another folder by comparing the ino to the library files
 | ||||||
|   const ino = await fileUtils.getIno(fullPath) |   const ino = await fileUtils.getIno(fullPath) | ||||||
|   if (!ino) return null |   if (!ino) return null | ||||||
|   const existingLibraryItem = await Database.libraryItemModel.findOneOld([ |   const existingLibraryItem = await Database.libraryItemModel.findOneOld( | ||||||
|  |     [ | ||||||
|       { |       { | ||||||
|         libraryId: libraryId |         libraryId: libraryId | ||||||
|       }, |       }, | ||||||
|       sequelize.where(sequelize.literal('(SELECT count(*) FROM json_each(libraryFiles) WHERE json_valid(json_each.value) AND json_each.value->>"$.ino" = :inode)'), { |       sequelize.where(sequelize.literal('(SELECT count(*) FROM json_each(libraryFiles) WHERE json_valid(json_each.value) AND json_each.value->>"$.ino" = :inode)'), { | ||||||
|         [sequelize.Op.gt]: 0 |         [sequelize.Op.gt]: 0 | ||||||
|       }) |       }) | ||||||
|   ], { |     ], | ||||||
|  |     { | ||||||
|       inode: ino |       inode: ino | ||||||
|   }) |     } | ||||||
|   if (existingLibraryItem) |   ) | ||||||
|     Logger.debug(`[LibraryScanner] Found library item with a library file matching inode "${ino}" at path "${existingLibraryItem.path}"`) |   if (existingLibraryItem) Logger.debug(`[LibraryScanner] Found library item with a library file matching inode "${ino}" at path "${existingLibraryItem.path}"`) | ||||||
|   return existingLibraryItem |   return existingLibraryItem | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -667,7 +684,6 @@ async function findLibraryItemByFileToItemInoMatch(libraryId, fullPath, isSingle | |||||||
|       [sequelize.Op.in]: itemFileInos |       [sequelize.Op.in]: itemFileInos | ||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
|   if (existingLibraryItem) |   if (existingLibraryItem) Logger.debug(`[LibraryScanner] Found library item with inode matching one of "${itemFileInos.join(',')}" at path "${existingLibraryItem.path}"`) | ||||||
|     Logger.debug(`[LibraryScanner] Found library item with inode matching one of "${itemFileInos.join(',')}" at path "${existingLibraryItem.path}"`) |  | ||||||
|   return existingLibraryItem |   return existingLibraryItem | ||||||
| } | } | ||||||
| @ -83,7 +83,7 @@ module.exports = { | |||||||
|    * @param {*} payload |    * @param {*} payload | ||||||
|    * @param {string} seriesId |    * @param {string} seriesId | ||||||
|    * @param {import('../models/User')} user |    * @param {import('../models/User')} user | ||||||
|    * @param {import('../objects/Library')} library |    * @param {import('../models/Library')} library | ||||||
|    * @returns {Object[]} |    * @returns {Object[]} | ||||||
|    */ |    */ | ||||||
|   async handleCollapseSubseries(payload, seriesId, user, library) { |   async handleCollapseSubseries(payload, seriesId, user, library) { | ||||||
|  | |||||||
| @ -15,12 +15,12 @@ module.exports = { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get library items using filter and sort |    * Get library items using filter and sort | ||||||
|    * @param {import('../../objects/Library')} library |    * @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 {object} { libraryItems:LibraryItem[], count:number } | ||||||
|    */ |    */ | ||||||
|   async getFilteredLibraryItems(library, 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 | ||||||
| 
 | 
 | ||||||
|     let filterValue = null |     let filterValue = null | ||||||
| @ -33,22 +33,22 @@ module.exports = { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (mediaType === 'book') { |     if (mediaType === 'book') { | ||||||
|       return libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset) |       return libraryItemsBookFilters.getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset) | ||||||
|     } else { |     } else { | ||||||
|       return libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, user, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset) |       return libraryItemsPodcastFilters.getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset) | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get library items for continue listening & continue reading shelves |    * Get library items for continue listening & continue reading shelves | ||||||
|    * @param {import('../../objects/Library')} library |    * @param {import('../../models/Library')} library | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {string[]} include |    * @param {string[]} include | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
|    * @returns {Promise<{ items:import('../../models/LibraryItem')[], count:number }>} |    * @returns {Promise<{ items:import('../../models/LibraryItem')[], count:number }>} | ||||||
|    */ |    */ | ||||||
|   async getMediaItemsInProgress(library, user, include, limit) { |   async getMediaItemsInProgress(library, user, include, limit) { | ||||||
|     if (library.mediaType === 'book') { |     if (library.isBook) { | ||||||
|       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) => { | ||||||
| @ -78,14 +78,14 @@ module.exports = { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get library items for most recently added shelf |    * Get library items for most recently added shelf | ||||||
|    * @param {import('../../objects/Library')} library |    * @param {import('../../models/Library')} library | ||||||
|    * @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 {object} { libraryItems:LibraryItem[], count:number } | ||||||
|    */ |    */ | ||||||
|   async getLibraryItemsMostRecentlyAdded(library, user, include, limit) { |   async getLibraryItemsMostRecentlyAdded(library, user, include, limit) { | ||||||
|     if (library.mediaType === 'book') { |     if (library.isBook) { | ||||||
|       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) => { | ||||||
| @ -126,7 +126,7 @@ module.exports = { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get library items for continue series shelf |    * Get library items for continue series shelf | ||||||
|    * @param {import('../../objects/Library')} library |    * @param {import('../../models/Library')} library | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {string[]} include |    * @param {string[]} include | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
| @ -154,14 +154,15 @@ module.exports = { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get library items or podcast episodes for the "Listen Again" and "Read Again" shelf |    * Get library items or podcast episodes for the "Listen Again" and "Read Again" shelf | ||||||
|    * @param {import('../../objects/Library')} library |    * | ||||||
|  |    * @param {import('../../models/Library')} library | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {string[]} include |    * @param {string[]} include | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
|    * @returns {object} { items:object[], count:number } |    * @returns {Promise<{ items:oldLibraryItem[], count:number }>} | ||||||
|    */ |    */ | ||||||
|   async getMediaFinished(library, user, include, limit) { |   async getMediaFinished(library, user, include, limit) { | ||||||
|     if (library.mediaType === 'book') { |     if (library.isBook) { | ||||||
|       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) => { | ||||||
| @ -191,7 +192,7 @@ module.exports = { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get series for recent series shelf |    * Get series for recent series shelf | ||||||
|    * @param {import('../../objects/Library')} library |    * @param {import('../../models/Library')} library | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {string[]} include |    * @param {string[]} include | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
| @ -316,10 +317,11 @@ module.exports = { | |||||||
|   /** |   /** | ||||||
|    * Get most recently created authors for "Newest Authors" shelf |    * Get most recently created authors for "Newest Authors" shelf | ||||||
|    * Author must be linked to at least 1 book |    * Author must be linked to at least 1 book | ||||||
|    * @param {oldLibrary} library |    * | ||||||
|  |    * @param {import('../../models/Library')} library | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
|    * @returns {object} { authors:oldAuthor[], count:number } |    * @returns {Promise<{ authors:oldAuthor[], count:number }>} | ||||||
|    */ |    */ | ||||||
|   async getNewestAuthors(library, user, limit) { |   async getNewestAuthors(library, user, limit) { | ||||||
|     if (library.mediaType !== 'book') return { authors: [], count: 0 } |     if (library.mediaType !== 'book') return { authors: [], count: 0 } | ||||||
| @ -359,11 +361,11 @@ module.exports = { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get book library items for the "Discover" shelf |    * Get book library items for the "Discover" shelf | ||||||
|    * @param {oldLibrary} library |    * @param {import('../../models/Library')} library | ||||||
|    * @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:oldLibraryItem[], count:number} |    * @returns {Promise<{libraryItems:oldLibraryItem[], count:number}>} | ||||||
|    */ |    */ | ||||||
|   async getLibraryItemsToDiscover(library, user, include, limit) { |   async getLibraryItemsToDiscover(library, user, include, limit) { | ||||||
|     if (library.mediaType !== 'book') return { libraryItems: [], count: 0 } |     if (library.mediaType !== 'book') return { libraryItems: [], count: 0 } | ||||||
| @ -386,10 +388,10 @@ module.exports = { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Get podcast episodes most recently added |    * Get podcast episodes most recently added | ||||||
|    * @param {oldLibrary} library |    * @param {import('../../models/Library')} library | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
|    * @returns {object} {libraryItems:oldLibraryItem[], count:number} |    * @returns {Promise<{libraryItems:oldLibraryItem[], count:number}>} | ||||||
|    */ |    */ | ||||||
|   async getNewestPodcastEpisodes(library, user, limit) { |   async getNewestPodcastEpisodes(library, user, limit) { | ||||||
|     if (library.mediaType !== 'podcast') return { libraryItems: [], count: 0 } |     if (library.mediaType !== 'podcast') return { libraryItems: [], count: 0 } | ||||||
| @ -411,7 +413,7 @@ module.exports = { | |||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
|    * @param {number} offset |    * @param {number} offset | ||||||
|    * @returns {Promise<object>} { libraryItems:LibraryItem[], count:number } |    * @returns {Promise<{ libraryItems:import('../../objects/LibraryItem')[], count:number }>} | ||||||
|    */ |    */ | ||||||
|   async getLibraryItemsForAuthor(author, user, limit, offset) { |   async getLibraryItemsForAuthor(author, user, limit, offset) { | ||||||
|     const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(author.libraryId, user, 'authors', author.id, 'addedAt', true, false, [], limit, offset) |     const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(author.libraryId, user, 'authors', author.id, 'addedAt', true, false, [], limit, offset) | ||||||
| @ -424,7 +426,7 @@ module.exports = { | |||||||
|   /** |   /** | ||||||
|    * Get book library items in a collection |    * Get book library items in a collection | ||||||
|    * @param {oldCollection} collection |    * @param {oldCollection} collection | ||||||
|    * @returns {Promise<LibraryItem[]>} |    * @returns {Promise<import('../../models/LibraryItem')[]>} | ||||||
|    */ |    */ | ||||||
|   getLibraryItemsForCollection(collection) { |   getLibraryItemsForCollection(collection) { | ||||||
|     return libraryItemsBookFilters.getLibraryItemsForCollection(collection) |     return libraryItemsBookFilters.getLibraryItemsForCollection(collection) | ||||||
|  | |||||||
| @ -636,7 +636,7 @@ module.exports = { | |||||||
|    * 2. Has no books in progress |    * 2. Has no books in progress | ||||||
|    * 3. Has at least 1 unfinished book |    * 3. Has at least 1 unfinished book | ||||||
|    * TODO: Reduce queries |    * TODO: Reduce queries | ||||||
|    * @param {import('../../objects/Library')} library |    * @param {import('../../models/Library')} library | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {string[]} include |    * @param {string[]} include | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
| @ -911,7 +911,7 @@ module.exports = { | |||||||
|   /** |   /** | ||||||
|    * Get book library items in a collection |    * Get book library items in a collection | ||||||
|    * @param {oldCollection} collection |    * @param {oldCollection} collection | ||||||
|    * @returns {Promise<LibraryItem[]>} |    * @returns {Promise<import('../../models/LibraryItem')[]>} | ||||||
|    */ |    */ | ||||||
|   async getLibraryItemsForCollection(collection) { |   async getLibraryItemsForCollection(collection) { | ||||||
|     if (!collection?.books?.length) { |     if (!collection?.books?.length) { | ||||||
|  | |||||||
| @ -412,12 +412,12 @@ module.exports = { | |||||||
|   /** |   /** | ||||||
|    * Most recent podcast episodes not finished |    * Most recent podcast episodes not finished | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {import('../../objects/Library')} oldLibrary |    * @param {import('../../models/Library')} library | ||||||
|    * @param {number} limit |    * @param {number} limit | ||||||
|    * @param {number} offset |    * @param {number} offset | ||||||
|    * @returns {Promise<object[]>} |    * @returns {Promise<object[]>} | ||||||
|    */ |    */ | ||||||
|   async getRecentEpisodes(user, oldLibrary, limit, offset) { |   async getRecentEpisodes(user, library, limit, offset) { | ||||||
|     const userPermissionPodcastWhere = this.getUserPermissionPodcastWhereQuery(user) |     const userPermissionPodcastWhere = this.getUserPermissionPodcastWhereQuery(user) | ||||||
| 
 | 
 | ||||||
|     const episodes = await Database.podcastEpisodeModel.findAll({ |     const episodes = await Database.podcastEpisodeModel.findAll({ | ||||||
| @ -435,7 +435,7 @@ module.exports = { | |||||||
|           include: { |           include: { | ||||||
|             model: Database.libraryItemModel, |             model: Database.libraryItemModel, | ||||||
|             where: { |             where: { | ||||||
|               libraryId: oldLibrary.id |               libraryId: library.id | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ module.exports = { | |||||||
|   /** |   /** | ||||||
|    * Get series filtered and sorted |    * Get series filtered and sorted | ||||||
|    * |    * | ||||||
|    * @param {import('../../objects/Library')} library |    * @param {import('../../models/Library')} library | ||||||
|    * @param {import('../../models/User')} user |    * @param {import('../../models/User')} user | ||||||
|    * @param {string} filterBy |    * @param {string} filterBy | ||||||
|    * @param {string} sortBy |    * @param {string} sortBy | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user