diff --git a/docs/objects/Notification.yaml b/docs/objects/Notification.yaml index 50299ec8b..05c7d9376 100644 --- a/docs/objects/Notification.yaml +++ b/docs/objects/Notification.yaml @@ -22,7 +22,7 @@ components: notificationEventName: type: string description: The name of the event the notification will fire on. - enum: ['onPodcastEpisodeDownloaded', 'onBackupCompleted', 'onBackupFailed', 'onTest'] + enum: ['onItemsAdded', 'onPodcastEpisodeDownloaded', 'onBackupCompleted', 'onBackupFailed', 'onTest'] urls: type: array items: diff --git a/docs/openapi.json b/docs/openapi.json index 48f30ecfb..bab29e157 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -3225,6 +3225,7 @@ "type": "string", "description": "The name of the event the notification will fire on.", "enum": [ + "onItemsAdded", "onPodcastEpisodeDownloaded", "onBackupCompleted", "onBackupFailed", diff --git a/server/managers/NotificationManager.js b/server/managers/NotificationManager.js index a59c12815..dffc642f3 100644 --- a/server/managers/NotificationManager.js +++ b/server/managers/NotificationManager.js @@ -14,6 +14,32 @@ class NotificationManager { return notificationData } + async onItemsAdded(LibraryItems) { + if (!Database.notificationSettings.isUseable) return + + if (!Database.notificationSettings.getHasActiveNotificationsForEvent('onItemsAdded')) { + Logger.debug(`[NotificationManager] onItemsAdded: No active notifications`) + return + } + + for (const item of LibraryItems) { + Logger.debug(`[NotificationManager] onItemsAdded: Item "${item.media.metadata.title}"`) + const library = await Database.libraryModel.findByPk(item.libraryId) + const eventData = { + libraryItemId: item.id, + libraryId: item.libraryId, + libraryName: library?.name || 'Unknown', + tags: (item.media.tags || []).join(', ') || 'None', + title: item.media.metadata.title, + authors: (item.media.metadata.authors.map(a => a.name) || []).join(', ') || '', + description: item.media.metadata.description || '', + genres: (item.media.metadata.genres || []).join(', ') || 'None', + publishedYear: item.media.metadata.publishedYear || '', + } + this.triggerNotification('onItemsAdded', eventData) + } + } + async onPodcastEpisodeDownloaded(libraryItem, episode) { if (!Database.notificationSettings.isUseable) return diff --git a/server/scanner/LibraryScanner.js b/server/scanner/LibraryScanner.js index bd0bb310f..02e261f39 100644 --- a/server/scanner/LibraryScanner.js +++ b/server/scanner/LibraryScanner.js @@ -16,7 +16,8 @@ const LibraryItemScanData = require('./LibraryItemScanData') const Task = require('../objects/Task') class LibraryScanner { - constructor() { + constructor(notificationManager) { + this.notificationManager = notificationManager this.cancelLibraryScan = {} /** @type {string[]} - library ids */ this.librariesScanning = [] @@ -284,6 +285,7 @@ class LibraryScanner { 'items_added', newOldLibraryItems.map((li) => li.toJSONExpanded()) ) + this.notificationManager.onItemsAdded(newOldLibraryItems) newOldLibraryItems = [] } @@ -296,6 +298,7 @@ class LibraryScanner { 'items_added', newOldLibraryItems.map((li) => li.toJSONExpanded()) ) + this.notificationManager.onItemsAdded(newOldLibraryItems) } } @@ -647,6 +650,7 @@ class LibraryScanner { if (newLibraryItem) { const oldNewLibraryItem = Database.libraryItemModel.getOldLibraryItem(newLibraryItem) SocketAuthority.emitter('item_added', oldNewLibraryItem.toJSONExpanded()) + this.notificationManager.onItemsAdded([oldNewLibraryItem]) } itemGroupingResults[itemDir] = newLibraryItem ? ScanResult.ADDED : ScanResult.NOTHING } @@ -654,7 +658,7 @@ class LibraryScanner { return itemGroupingResults } } -module.exports = new LibraryScanner() +module.exports = new LibraryScanner(new NotificationManager()) function ItemToFileInoMatch(libraryItem1, libraryItem2) { return libraryItem1.isFile && libraryItem2.libraryFiles.some((lf) => lf.ino === libraryItem1.ino) diff --git a/server/utils/notifications.js b/server/utils/notifications.js index 96e8ddf8c..a8e0e5866 100644 --- a/server/utils/notifications.js +++ b/server/utils/notifications.js @@ -2,6 +2,28 @@ const { version } = require('../../package.json') module.exports.notificationData = { events: [ + { + name: 'onItemsAdded', + requiresLibrary: true, + libraryMediaType: 'item', + description: 'Triggered when an item is added to the library', + variables: ['libraryItemId', 'libraryId', 'libraryName', 'tags', 'title', 'authors', 'description', 'genres', 'publishedYear'], + defaults: { + title: 'New Book!', + body: '{{title}} has been added to {{libraryName}} library.' + }, + testData: { + libraryItemId: 'li_notification_test', + libraryId: 'lib_test', + libraryName: 'My Library', + tags: 'TestTag1, TestTag2', + title: 'ABS Test Book', + authors: 'Author1, Author2', + description: 'Description of the Abs Test Book belongs here.', + genres: 'TestGenre1, TestGenre2', + publishedYear: '2020' + } + }, { name: 'onPodcastEpisodeDownloaded', requiresLibrary: true,