Add notification for manually downloaded podcast episodes

This commit is contained in:
Ben 2026-08-01 11:11:45 -06:00
parent 2d9f63963e
commit b5feacb28f
6 changed files with 69 additions and 12 deletions

View file

@ -954,6 +954,7 @@
"NotificationOnBackupCompletedDescription": "Triggered when a backup is completed", "NotificationOnBackupCompletedDescription": "Triggered when a backup is completed",
"NotificationOnBackupFailedDescription": "Triggered when a backup fails", "NotificationOnBackupFailedDescription": "Triggered when a backup fails",
"NotificationOnEpisodeDownloadedDescription": "Triggered when a podcast episode is auto-downloaded", "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", "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", "NotificationOnRSSFeedFailedDescription": "Triggered when the RSS feed request fails for an automatic episode download",
"NotificationOnTestDescription": "Event for testing the notification system", "NotificationOnTestDescription": "Event for testing the notification system",

View file

@ -22,7 +22,7 @@ components:
notificationEventName: notificationEventName:
type: string type: string
description: The name of the event the notification will fire on. description: The name of the event the notification will fire on.
enum: ['onPodcastEpisodeDownloaded', 'onBackupCompleted', 'onBackupFailed', 'onTest'] enum: ['onPodcastEpisodeDownloaded', 'onPodcastEpisodeManuallyDownloaded', 'onBackupCompleted', 'onBackupFailed', 'onTest']
urls: urls:
type: array type: array
items: items:

View file

@ -3226,6 +3226,7 @@
"description": "The name of the event the notification will fire on.", "description": "The name of the event the notification will fire on.",
"enum": [ "enum": [
"onPodcastEpisodeDownloaded", "onPodcastEpisodeDownloaded",
"onPodcastEpisodeManuallyDownloaded",
"onBackupCompleted", "onBackupCompleted",
"onBackupFailed", "onBackupFailed",
"onTest" "onTest"

View file

@ -18,18 +18,11 @@ class NotificationManager {
* *
* @param {import('../models/LibraryItem')} libraryItem * @param {import('../models/LibraryItem')} libraryItem
* @param {import('../models/PodcastEpisode')} episode * @param {import('../models/PodcastEpisode')} episode
* @returns {Promise<object>}
*/ */
async onPodcastEpisodeDownloaded(libraryItem, episode) { async getPodcastEpisodeDownloadedEventData(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 library = await Database.libraryModel.findByPk(libraryItem.libraryId) const library = await Database.libraryModel.findByPk(libraryItem.libraryId)
const eventData = { return {
libraryItemId: libraryItem.id, libraryItemId: libraryItem.id,
libraryId: libraryItem.libraryId, libraryId: libraryItem.libraryId,
libraryName: library?.name || 'Unknown', libraryName: library?.name || 'Unknown',
@ -43,9 +36,44 @@ class NotificationManager {
episodeSubtitle: episode.subtitle || '', episodeSubtitle: episode.subtitle || '',
episodeDescription: episode.description || '' 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) 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 * @param {import('../objects/Backup')} backup

View file

@ -256,8 +256,9 @@ class PodcastManager {
SocketAuthority.emitter('episode_added', podcastEpisodeExpanded) SocketAuthority.emitter('episode_added', podcastEpisodeExpanded)
if (this.currentDownload.isAutoDownload) { if (this.currentDownload.isAutoDownload) {
// Notifications only for auto downloaded episodes
NotificationManager.onPodcastEpisodeDownloaded(libraryItem, podcastEpisode) NotificationManager.onPodcastEpisodeDownloaded(libraryItem, podcastEpisode)
} else {
NotificationManager.onPodcastEpisodeManuallyDownloaded(libraryItem, podcastEpisode)
} }
return true return true

View file

@ -28,6 +28,32 @@ module.exports.notificationData = {
episodeDescription: 'Some description of the podcast episode.' 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', name: 'onBackupCompleted',
requiresLibrary: false, requiresLibrary: false,