diff --git a/client/strings/en-us.json b/client/strings/en-us.json index d9d6325e4..db4119c57 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -958,6 +958,7 @@ "NotificationOnBackupCompletedDescription": "Triggered when a backup is completed", "NotificationOnBackupFailedDescription": "Triggered when a backup fails", "NotificationOnEpisodeDownloadedDescription": "Triggered when a podcast episode is auto-downloaded", + "NotificationOnEpisodeManuallyDownloadedDescription": "Triggered when a podcast episode is manually downloaded", "NotificationOnRSSFeedDisabledDescription": "Triggered when automatic episode downloads are disabled due to too many failed attempts", "NotificationOnRSSFeedFailedDescription": "Triggered when the RSS feed request fails for an automatic episode download", "NotificationOnTestDescription": "Event for testing the notification system", diff --git a/docs/objects/Notification.yaml b/docs/objects/Notification.yaml index 50299ec8b..cd94be4d4 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: ['onPodcastEpisodeDownloaded', 'onPodcastEpisodeManuallyDownloaded', 'onBackupCompleted', 'onBackupFailed', 'onTest'] urls: type: array items: diff --git a/docs/openapi.json b/docs/openapi.json index 48f30ecfb..07957cf8c 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -3226,6 +3226,7 @@ "description": "The name of the event the notification will fire on.", "enum": [ "onPodcastEpisodeDownloaded", + "onPodcastEpisodeManuallyDownloaded", "onBackupCompleted", "onBackupFailed", "onTest" diff --git a/server/managers/NotificationManager.js b/server/managers/NotificationManager.js index 567da38ec..9bc91ffaf 100644 --- a/server/managers/NotificationManager.js +++ b/server/managers/NotificationManager.js @@ -18,18 +18,11 @@ class NotificationManager { * * @param {import('../models/LibraryItem')} libraryItem * @param {import('../models/PodcastEpisode')} episode + * @returns {Promise} */ - async onPodcastEpisodeDownloaded(libraryItem, episode) { - if (!Database.notificationSettings.isUseable) return - - if (!Database.notificationSettings.getHasActiveNotificationsForEvent('onPodcastEpisodeDownloaded')) { - Logger.debug(`[NotificationManager] onPodcastEpisodeDownloaded: No active notifications`) - return - } - - Logger.debug(`[NotificationManager] onPodcastEpisodeDownloaded: Episode "${episode.title}" for podcast ${libraryItem.media.title}`) + async getPodcastEpisodeDownloadedEventData(libraryItem, episode) { const library = await Database.libraryModel.findByPk(libraryItem.libraryId) - const eventData = { + return { libraryItemId: libraryItem.id, libraryId: libraryItem.libraryId, libraryName: library?.name || 'Unknown', @@ -43,9 +36,44 @@ class NotificationManager { episodeSubtitle: episode.subtitle || '', episodeDescription: episode.description || '' } + } + + /** + * + * @param {import('../models/LibraryItem')} libraryItem + * @param {import('../models/PodcastEpisode')} episode + */ + async onPodcastEpisodeDownloaded(libraryItem, episode) { + if (!Database.notificationSettings.isUseable) return + + if (!Database.notificationSettings.getHasActiveNotificationsForEvent('onPodcastEpisodeDownloaded')) { + Logger.debug(`[NotificationManager] onPodcastEpisodeDownloaded: No active notifications`) + return + } + + Logger.debug(`[NotificationManager] onPodcastEpisodeDownloaded: Episode "${episode.title}" for podcast ${libraryItem.media.title}`) + const eventData = await this.getPodcastEpisodeDownloadedEventData(libraryItem, episode) this.triggerNotification('onPodcastEpisodeDownloaded', eventData) } + /** + * + * @param {import('../models/LibraryItem')} libraryItem + * @param {import('../models/PodcastEpisode')} episode + */ + async onPodcastEpisodeManuallyDownloaded(libraryItem, episode) { + if (!Database.notificationSettings.isUseable) return + + if (!Database.notificationSettings.getHasActiveNotificationsForEvent('onPodcastEpisodeManuallyDownloaded')) { + Logger.debug(`[NotificationManager] onPodcastEpisodeManuallyDownloaded: No active notifications`) + return + } + + Logger.debug(`[NotificationManager] onPodcastEpisodeManuallyDownloaded: Episode "${episode.title}" for podcast ${libraryItem.media.title}`) + const eventData = await this.getPodcastEpisodeDownloadedEventData(libraryItem, episode) + this.triggerNotification('onPodcastEpisodeManuallyDownloaded', eventData) + } + /** * * @param {import('../objects/Backup')} backup diff --git a/server/managers/PodcastManager.js b/server/managers/PodcastManager.js index bdf6fc764..86ecabe02 100644 --- a/server/managers/PodcastManager.js +++ b/server/managers/PodcastManager.js @@ -256,8 +256,9 @@ class PodcastManager { SocketAuthority.emitter('episode_added', podcastEpisodeExpanded) if (this.currentDownload.isAutoDownload) { - // Notifications only for auto downloaded episodes NotificationManager.onPodcastEpisodeDownloaded(libraryItem, podcastEpisode) + } else { + NotificationManager.onPodcastEpisodeManuallyDownloaded(libraryItem, podcastEpisode) } return true diff --git a/server/utils/notifications.js b/server/utils/notifications.js index 497d7a1a1..2374a10cf 100644 --- a/server/utils/notifications.js +++ b/server/utils/notifications.js @@ -28,6 +28,32 @@ module.exports.notificationData = { episodeDescription: 'Some description of the podcast episode.' } }, + { + name: 'onPodcastEpisodeManuallyDownloaded', + requiresLibrary: true, + libraryMediaType: 'podcast', + description: 'Triggered when a podcast episode is manually downloaded', + descriptionKey: 'NotificationOnEpisodeManuallyDownloadedDescription', + variables: ['libraryItemId', 'libraryId', 'podcastTitle', 'podcastAuthor', 'podcastDescription', 'podcastGenres', 'episodeTitle', 'episodeSubtitle', 'episodeDescription', 'libraryName', 'episodeId', 'mediaTags'], + defaults: { + title: 'New {{podcastTitle}} Episode!', + body: '{{episodeTitle}} has been added to {{libraryName}} library.' + }, + testData: { + libraryItemId: 'li_notification_test', + libraryId: 'lib_test', + libraryName: 'Podcasts', + mediaTags: 'TestTag1, TestTag2', + podcastTitle: 'Abs Test Podcast', + podcastAuthor: 'Audiobookshelf', + podcastDescription: 'Description of the Abs Test Podcast belongs here.', + podcastGenres: 'TestGenre1, TestGenre2', + episodeId: 'ep_notification_test', + episodeTitle: 'Successful Test Episode', + episodeSubtitle: 'Episode Subtitle', + episodeDescription: 'Some description of the podcast episode.' + } + }, { name: 'onBackupCompleted', requiresLibrary: false,