From 05db735214160f786316dbc0923505645e00ba27 Mon Sep 17 00:00:00 2001 From: chiragkrishna Date: Sun, 8 Sep 2024 11:12:27 +0530 Subject: [PATCH 1/5] Add-notification-for-item-deleted --- Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs b/Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs index 131f790..9550a38 100644 --- a/Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs +++ b/Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs @@ -13,6 +13,7 @@ using Jellyfin.Plugin.Webhook.Helpers; using Jellyfin.Plugin.Webhook.Notifiers; using Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier; +using Jellyfin.Plugin.Webhook.Notifiers.ItemDeletedNotifier; using Jellyfin.Plugin.Webhook.Notifiers.UserDataSavedNotifier; using MediaBrowser.Common.Updates; using MediaBrowser.Controller; @@ -58,6 +59,7 @@ public void RegisterServices(IServiceCollection serviceCollection, IServerApplic // Library consumers. serviceCollection.AddScoped, SubtitleDownloadFailureNotifier>(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); // Security consumers. serviceCollection.AddScoped, AuthenticationFailureNotifier>(); @@ -90,6 +92,7 @@ public void RegisterServices(IServiceCollection serviceCollection, IServerApplic serviceCollection.AddHostedService(); serviceCollection.AddHostedService(); + serviceCollection.AddHostedService(); serviceCollection.AddHostedService(); } } From eb04b6a4870f46dde350cb044af7a4d36ef46565 Mon Sep 17 00:00:00 2001 From: chiragkrishna Date: Sun, 8 Sep 2024 11:13:00 +0530 Subject: [PATCH 2/5] Add-notification-for-item-deleted --- Jellyfin.Plugin.Webhook/Configuration/Web/config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Jellyfin.Plugin.Webhook/Configuration/Web/config.js b/Jellyfin.Plugin.Webhook/Configuration/Web/config.js index b50b6ee..f29ed49 100644 --- a/Jellyfin.Plugin.Webhook/Configuration/Web/config.js +++ b/Jellyfin.Plugin.Webhook/Configuration/Web/config.js @@ -40,6 +40,7 @@ export default function (view) { template: document.querySelector("#template-notification-type"), values: { "ItemAdded": "Item Added", + "ItemDeleted": "Item Deleted", "PlaybackStart": "Playback Start", "PlaybackProgress": "Playback Progress", "PlaybackStop": "Playback Stop", From 150058aba603924767a093c84fa0afff8868401c Mon Sep 17 00:00:00 2001 From: chiragkrishna Date: Sun, 8 Sep 2024 11:13:47 +0530 Subject: [PATCH 3/5] Add-notification-for-item-deleted --- Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs b/Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs index 27fce7f..b647b0b 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs @@ -123,5 +123,10 @@ public enum NotificationType /// /// User data saved. /// - UserDataSaved = 23 + UserDataSaved = 23, + + /// + /// Item Deleted notification. + /// + ItemDeleted = 24 } From 64f9c8eac189b4c919c5de72f179136f20eeacbd Mon Sep 17 00:00:00 2001 From: chiragkrishna Date: Sun, 8 Sep 2024 11:14:32 +0530 Subject: [PATCH 4/5] Add-notification-for-item-deleted --- .../IItemDeletedManager.cs | 22 +++++ .../ItemDeletedNotifier/ItemDeletedManager.cs | 90 +++++++++++++++++++ .../ItemDeletedNotifierEntryPoint.cs | 53 +++++++++++ .../ItemDeletedScheduledTask.cs | 71 +++++++++++++++ 4 files changed, 236 insertions(+) create mode 100644 Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/IItemDeletedManager.cs create mode 100644 Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs create mode 100644 Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedNotifierEntryPoint.cs create mode 100644 Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedScheduledTask.cs diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/IItemDeletedManager.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/IItemDeletedManager.cs new file mode 100644 index 0000000..b80e569 --- /dev/null +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/IItemDeletedManager.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using MediaBrowser.Controller.Entities; + +namespace Jellyfin.Plugin.Webhook.Notifiers.ItemDeletedNotifier; + +/// +/// Item deleted manager interface. +/// +public interface IItemDeletedManager +{ + /// + /// Process the current queue. + /// + /// A representing the asynchronous operation. + public Task ProcessItemsAsync(); + + /// + /// Add item to process queue. + /// + /// The deleted item. + public void AddItem(BaseItem item); +} \ No newline at end of file diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs new file mode 100644 index 0000000..9624947 --- /dev/null +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Concurrent; +using System.Threading.Tasks; +using Jellyfin.Plugin.Webhook.Destinations; +using Jellyfin.Plugin.Webhook.Helpers; +using Jellyfin.Plugin.Webhook.Models; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Plugin.Webhook.Notifiers.ItemDeletedNotifier; + +/// +public class ItemDeletedManager : IItemDeletedManager +{ + private readonly ILogger _logger; + private readonly ILibraryManager _libraryManager; + private readonly IServerApplicationHost _applicationHost; + private readonly ConcurrentDictionary _itemProcessQueue; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public ItemDeletedManager( + ILogger logger, + ILibraryManager libraryManager, + IServerApplicationHost applicationHost) + { + _logger = logger; + _libraryManager = libraryManager; + _applicationHost = applicationHost; + _itemProcessQueue = new ConcurrentDictionary(); + } + + /// + public async Task ProcessItemsAsync() + { + _logger.LogDebug("ProcessItemsAsync"); + // Attempt to process all items in queue. + if (!_itemProcessQueue.IsEmpty) + { + var scope = _applicationHost.ServiceProvider!.CreateAsyncScope(); + await using (scope.ConfigureAwait(false)) + { + var webhookSender = scope.ServiceProvider.GetRequiredService(); + foreach (var (key, item) in _itemProcessQueue) + { + if (item != null) + { + _logger.LogDebug("Item {ItemName}", item.Name); + + // Skip notification if item type is Studio + if (item.GetType().Name == "Studio") + { + _logger.LogDebug("Skipping notification for item type Studio"); + _itemProcessQueue.TryRemove(key, out _); + continue; + } + + _logger.LogDebug("Notifying for {ItemName}", item.Name); + + // Send notification to each configured destination. + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.ItemDeleted) + .AddBaseItemData(item); + + var itemType = item.GetType(); + await webhookSender.SendNotification(NotificationType.ItemDeleted, dataObject, itemType) + .ConfigureAwait(false); + + // Remove item from queue. + _itemProcessQueue.TryRemove(key, out _); + } + } + } + } + } + + /// + public void AddItem(BaseItem item) + { + _itemProcessQueue.TryAdd(item.Id, item); + _logger.LogDebug("Queued {ItemName} for notification", item.Name); + } +} \ No newline at end of file diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedNotifierEntryPoint.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedNotifierEntryPoint.cs new file mode 100644 index 0000000..f68245b --- /dev/null +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedNotifierEntryPoint.cs @@ -0,0 +1,53 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Library; +using Microsoft.Extensions.Hosting; + +namespace Jellyfin.Plugin.Webhook.Notifiers.ItemDeletedNotifier; + +/// +/// Notifier when a library item is deleted. +/// +public class ItemDeletedNotifierEntryPoint : IHostedService +{ + private readonly IItemDeletedManager _itemDeletedManager; + private readonly ILibraryManager _libraryManager; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + public ItemDeletedNotifierEntryPoint( + IItemDeletedManager itemDeletedManager, + ILibraryManager libraryManager) + { + _itemDeletedManager = itemDeletedManager; + _libraryManager = libraryManager; + } + + private void ItemDeletedHandler(object? sender, ItemChangeEventArgs itemChangeEventArgs) + { + // Never notify on virtual items. + if (itemChangeEventArgs.Item.IsVirtualItem) + { + return; + } + + _itemDeletedManager.AddItem(itemChangeEventArgs.Item); + } + + /// + public Task StartAsync(CancellationToken cancellationToken) + { + _libraryManager.ItemRemoved += ItemDeletedHandler; + return Task.CompletedTask; + } + + /// + public Task StopAsync(CancellationToken cancellationToken) + { + _libraryManager.ItemRemoved -= ItemDeletedHandler; + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedScheduledTask.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedScheduledTask.cs new file mode 100644 index 0000000..4e88336 --- /dev/null +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedScheduledTask.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Tasks; + +namespace Jellyfin.Plugin.Webhook.Notifiers.ItemDeletedNotifier; + +/// +/// Scheduled task that processes item deleted events. +/// +public class ItemDeletedScheduledTask : IScheduledTask, IConfigurableScheduledTask +{ + private const int RecheckIntervalSec = 30; + private readonly IItemDeletedManager _itemDeletedManager; + private readonly ILocalizationManager _localizationManager; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + public ItemDeletedScheduledTask( + IItemDeletedManager itemDeletedManager, + ILocalizationManager localizationManager) + { + _itemDeletedManager = itemDeletedManager; + _localizationManager = localizationManager; + } + + /// + public string Name => "Webhook Item Deleted Notifier"; + + /// + public string Key => "WebhookItemDeleted"; + + /// + public string Description => "Processes item deleted queue"; + + /// + public string Category => _localizationManager.GetLocalizedString("TasksLibraryCategory"); + + /// + public bool IsHidden => false; + + /// + public bool IsEnabled => true; + + /// + public bool IsLogged => false; + + /// + public Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken) + { + return _itemDeletedManager.ProcessItemsAsync(); + } + + /// + public IEnumerable GetDefaultTriggers() + { + return new[] + { + new TaskTriggerInfo + { + Type = TaskTriggerInfo.TriggerInterval, + IntervalTicks = TimeSpan.FromSeconds(RecheckIntervalSec).Ticks + } + }; + } +} \ No newline at end of file From 10bf1453fdb9332312050467c60005bf868a2b22 Mon Sep 17 00:00:00 2001 From: chiragkrishna Date: Sun, 8 Sep 2024 12:28:58 +0530 Subject: [PATCH 5/5] remove unnecessary using --- .../Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs index 9624947..b47f4f2 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemDeletedNotifier/ItemDeletedManager.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using Jellyfin.Plugin.Webhook.Destinations; using Jellyfin.Plugin.Webhook.Helpers; -using Jellyfin.Plugin.Webhook.Models; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -87,4 +86,4 @@ public void AddItem(BaseItem item) _itemProcessQueue.TryAdd(item.Id, item); _logger.LogDebug("Queued {ItemName} for notification", item.Name); } -} \ No newline at end of file +}