diff --git a/Jellyfin.Plugin.Webhook/Configuration/PluginConfiguration.cs b/Jellyfin.Plugin.Webhook/Configuration/PluginConfiguration.cs index 1bfcd3e..00675f2 100644 --- a/Jellyfin.Plugin.Webhook/Configuration/PluginConfiguration.cs +++ b/Jellyfin.Plugin.Webhook/Configuration/PluginConfiguration.cs @@ -10,78 +10,77 @@ using Jellyfin.Plugin.Webhook.Destinations.Slack; using Jellyfin.Plugin.Webhook.Destinations.Smtp; using MediaBrowser.Model.Plugins; -namespace Jellyfin.Plugin.Webhook.Configuration +namespace Jellyfin.Plugin.Webhook.Configuration; + +/// +/// Webhook plugin configuration. +/// +public class PluginConfiguration : BasePluginConfiguration { /// - /// Webhook plugin configuration. + /// Initializes a new instance of the class. /// - public class PluginConfiguration : BasePluginConfiguration + public PluginConfiguration() { - /// - /// Initializes a new instance of the class. - /// - public PluginConfiguration() - { - ServerUrl = string.Empty; - DiscordOptions = Array.Empty(); - GenericOptions = Array.Empty(); - GenericFormOptions = Array.Empty(); - GotifyOptions = Array.Empty(); - PushbulletOptions = Array.Empty(); - PushoverOptions = Array.Empty(); - SlackOptions = Array.Empty(); - SmtpOptions = Array.Empty(); - MqttOptions = Array.Empty(); - } - - /// - /// Gets or sets the jellyfin server url. - /// - public string ServerUrl { get; set; } - - /// - /// Gets or sets the discord options. - /// - public DiscordOption[] DiscordOptions { get; set; } - - /// - /// Gets or sets the generic options. - /// - public GenericOption[] GenericOptions { get; set; } - - /// - /// Gets or sets the generic form options. - /// - public GenericFormOption[] GenericFormOptions { get; set; } - - /// - /// Gets or sets the gotify options. - /// - public GotifyOption[] GotifyOptions { get; set; } - - /// - /// Gets or sets the pushbullet options. - /// - public PushbulletOption[] PushbulletOptions { get; set; } - - /// - /// Gets or sets the pushover options. - /// - public PushoverOption[] PushoverOptions { get; set; } - - /// - /// Gets or sets the slack options. - /// - public SlackOption[] SlackOptions { get; set; } - - /// - /// Gets or sets the smtp options. - /// - public SmtpOption[] SmtpOptions { get; set; } - - /// - /// Gets or sets the mqtt options. - /// - public MqttOption[] MqttOptions { get; set; } + ServerUrl = string.Empty; + DiscordOptions = Array.Empty(); + GenericOptions = Array.Empty(); + GenericFormOptions = Array.Empty(); + GotifyOptions = Array.Empty(); + PushbulletOptions = Array.Empty(); + PushoverOptions = Array.Empty(); + SlackOptions = Array.Empty(); + SmtpOptions = Array.Empty(); + MqttOptions = Array.Empty(); } + + /// + /// Gets or sets the jellyfin server url. + /// + public string ServerUrl { get; set; } + + /// + /// Gets or sets the discord options. + /// + public DiscordOption[] DiscordOptions { get; set; } + + /// + /// Gets or sets the generic options. + /// + public GenericOption[] GenericOptions { get; set; } + + /// + /// Gets or sets the generic form options. + /// + public GenericFormOption[] GenericFormOptions { get; set; } + + /// + /// Gets or sets the gotify options. + /// + public GotifyOption[] GotifyOptions { get; set; } + + /// + /// Gets or sets the pushbullet options. + /// + public PushbulletOption[] PushbulletOptions { get; set; } + + /// + /// Gets or sets the pushover options. + /// + public PushoverOption[] PushoverOptions { get; set; } + + /// + /// Gets or sets the slack options. + /// + public SlackOption[] SlackOptions { get; set; } + + /// + /// Gets or sets the smtp options. + /// + public SmtpOption[] SmtpOptions { get; set; } + + /// + /// Gets or sets the mqtt options. + /// + public MqttOption[] MqttOptions { get; set; } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/BaseClient.cs b/Jellyfin.Plugin.Webhook/Destinations/BaseClient.cs index a841f4a..2ac5fbd 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/BaseClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/BaseClient.cs @@ -2,39 +2,38 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Destinations +namespace Jellyfin.Plugin.Webhook.Destinations; + +/// +/// The base destination. +/// +public class BaseClient { /// - /// The base destination. + /// Determines whether the client should send the webhook. /// - public class BaseClient + /// Instance of the interface. + /// The sender option. + /// The webhook data. + /// Whether the client should send the webhook. + protected bool SendWebhook( + ILogger logger, + BaseOption option, + Dictionary data) { - /// - /// Determines whether the client should send the webhook. - /// - /// Instance of the interface. - /// The sender option. - /// The webhook data. - /// Whether the client should send the webhook. - protected bool SendWebhook( - ILogger logger, - BaseOption option, - Dictionary data) + var notificationType = data[nameof(NotificationType)] as NotificationType? ?? NotificationType.None; + + // Don't filter on UserId if the notification type is UserCreated. + if (notificationType is not NotificationType.UserCreated + && option.UserFilter.Length is not 0 + && data.TryGetValue("UserId", out var userIdObj) + && userIdObj is Guid userId + && Array.IndexOf(option.UserFilter, userId) is -1) { - var notificationType = data[nameof(NotificationType)] as NotificationType? ?? NotificationType.None; - - // Don't filter on UserId if the notification type is UserCreated. - if (notificationType is not NotificationType.UserCreated - && option.UserFilter.Length is not 0 - && data.TryGetValue("UserId", out var userIdObj) - && userIdObj is Guid userId - && Array.IndexOf(option.UserFilter, userId) is -1) - { - logger.LogDebug("UserId {UserId} not found in user filter, ignoring event", userId); - return false; - } - - return true; + logger.LogDebug("UserId {UserId} not found in user filter, ignoring event", userId); + return false; } + + return true; } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/BaseOption.cs b/Jellyfin.Plugin.Webhook/Destinations/BaseOption.cs index 5b68822..c51a0f7 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/BaseOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/BaseOption.cs @@ -5,97 +5,96 @@ using HandlebarsDotNet; using Jellyfin.Extensions.Json; using Jellyfin.Plugin.Webhook.Helpers; -namespace Jellyfin.Plugin.Webhook.Destinations +namespace Jellyfin.Plugin.Webhook.Destinations; + +/// +/// Base options for destination. +/// +public abstract class BaseOption { + private HandlebarsTemplate? _compiledTemplate; + /// - /// Base options for destination. + /// Gets or sets the notification type. /// - public abstract class BaseOption + public NotificationType[] NotificationTypes { get; set; } = Array.Empty(); + + /// + /// Gets or sets the webhook name. + /// + /// + /// Only used for display. + /// + public string? WebhookName { get; set; } + + /// + /// Gets or sets the webhook uri. + /// + public string? WebhookUri { get; set; } + + /// + /// Gets or sets a value indicating whether to notify on movies. + /// + public bool EnableMovies { get; set; } + + /// + /// Gets or sets a value indicating whether to notify on episodes. + /// + public bool EnableEpisodes { get; set; } + + /// + /// Gets or sets a value indicating whether to notify on series. + /// + public bool EnableSeries { get; set; } + + /// + /// Gets or sets a value indicating whether to notify on seasons. + /// + public bool EnableSeasons { get; set; } + + /// + /// Gets or sets a value indicating whether to notify on albums. + /// + public bool EnableAlbums { get; set; } + + /// + /// Gets or sets a value indicating whether to notify on songs. + /// + public bool EnableSongs { get; set; } + + /// + /// Gets or sets a value indicating whether to send all possible properties. + /// + public bool SendAllProperties { get; set; } + + /// + /// Gets or sets the handlebars template. + /// + public string? Template { get; set; } + + /// + /// Gets or sets the webhook user filter. + /// + public Guid[] UserFilter { get; set; } = Array.Empty(); + + /// + /// Gets the compiled handlebars template. + /// + /// The compiled handlebars template. + public HandlebarsTemplate GetCompiledTemplate() { - private HandlebarsTemplate? _compiledTemplate; + return _compiledTemplate ??= Handlebars.Compile(HandlebarsFunctionHelpers.Base64Decode(Template)); + } - /// - /// Gets or sets the notification type. - /// - public NotificationType[] NotificationTypes { get; set; } = Array.Empty(); - - /// - /// Gets or sets the webhook name. - /// - /// - /// Only used for display. - /// - public string? WebhookName { get; set; } - - /// - /// Gets or sets the webhook uri. - /// - public string? WebhookUri { get; set; } - - /// - /// Gets or sets a value indicating whether to notify on movies. - /// - public bool EnableMovies { get; set; } - - /// - /// Gets or sets a value indicating whether to notify on episodes. - /// - public bool EnableEpisodes { get; set; } - - /// - /// Gets or sets a value indicating whether to notify on series. - /// - public bool EnableSeries { get; set; } - - /// - /// Gets or sets a value indicating whether to notify on seasons. - /// - public bool EnableSeasons { get; set; } - - /// - /// Gets or sets a value indicating whether to notify on albums. - /// - public bool EnableAlbums { get; set; } - - /// - /// Gets or sets a value indicating whether to notify on songs. - /// - public bool EnableSongs { get; set; } - - /// - /// Gets or sets a value indicating whether to send all possible properties. - /// - public bool SendAllProperties { get; set; } - - /// - /// Gets or sets the handlebars template. - /// - public string? Template { get; set; } - - /// - /// Gets or sets the webhook user filter. - /// - public Guid[] UserFilter { get; set; } = Array.Empty(); - - /// - /// Gets the compiled handlebars template. - /// - /// The compiled handlebars template. - public HandlebarsTemplate GetCompiledTemplate() - { - return _compiledTemplate ??= Handlebars.Compile(HandlebarsFunctionHelpers.Base64Decode(Template)); - } - - /// - /// Gets the message body. - /// - /// The notification body. - /// The string message body. - public string GetMessageBody(Dictionary data) - { - return SendAllProperties - ? JsonSerializer.Serialize(data, JsonDefaults.Options) - : GetCompiledTemplate()(data); - } + /// + /// Gets the message body. + /// + /// The notification body. + /// The string message body. + public string GetMessageBody(Dictionary data) + { + return SendAllProperties + ? JsonSerializer.Serialize(data, JsonDefaults.Options) + : GetCompiledTemplate()(data); } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordClient.cs index 43a8fb9..3ccc1a8 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordClient.cs @@ -9,88 +9,87 @@ using Jellyfin.Plugin.Webhook.Extensions; using MediaBrowser.Common.Net; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Destinations.Discord +namespace Jellyfin.Plugin.Webhook.Destinations.Discord; + +/// +/// Client for the . +/// +public class DiscordClient : BaseClient, IWebhookClient { + private readonly ILogger _logger; + private readonly IHttpClientFactory _httpClientFactory; + /// - /// Client for the . + /// Initializes a new instance of the class. /// - public class DiscordClient : BaseClient, IWebhookClient + /// Instance of the interface. + /// Instance of the interface. + public DiscordClient(ILogger logger, IHttpClientFactory httpClientFactory) { - private readonly ILogger _logger; - private readonly IHttpClientFactory _httpClientFactory; + _logger = logger; + _httpClientFactory = httpClientFactory; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public DiscordClient(ILogger logger, IHttpClientFactory httpClientFactory) + /// + public async Task SendAsync(DiscordOption option, Dictionary data) + { + try { - _logger = logger; - _httpClientFactory = httpClientFactory; - } - - /// - public async Task SendAsync(DiscordOption option, Dictionary data) - { - try + if (string.IsNullOrEmpty(option.WebhookUri)) { - if (string.IsNullOrEmpty(option.WebhookUri)) - { - throw new ArgumentException(nameof(option.WebhookUri)); - } - - if (!SendWebhook(_logger, option, data)) - { - return; - } - - // Add discord specific properties. - data["MentionType"] = GetMentionType(option.MentionType); - if (!string.IsNullOrEmpty(option.EmbedColor)) - { - data["EmbedColor"] = FormatColorCode(option.EmbedColor); - } - - if (!string.IsNullOrEmpty(option.AvatarUrl)) - { - data["AvatarUrl"] = option.AvatarUrl; - } - - if (!string.IsNullOrEmpty(option.Username)) - { - data["Username"] = option.Username; - data["BotUsername"] = option.Username; - } - - var body = option.GetMessageBody(data); - _logger.LogDebug("SendAsync Body: {@Body}", body); - using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); - using var response = await _httpClientFactory - .CreateClient(NamedClient.Default) - .PostAsync(new Uri(option.WebhookUri), content) - .ConfigureAwait(false); - await response.LogIfFailedAsync(_logger).ConfigureAwait(false); + throw new ArgumentException(nameof(option.WebhookUri)); } - catch (HttpRequestException e) + + if (!SendWebhook(_logger, option, data)) { - _logger.LogWarning(e, "Error sending notification"); + return; } - } - private static int FormatColorCode(string hexCode) - { - return int.Parse(hexCode[1..6], NumberStyles.HexNumber, CultureInfo.InvariantCulture); - } - - private static string GetMentionType(DiscordMentionType mentionType) - { - return mentionType switch + // Add discord specific properties. + data["MentionType"] = GetMentionType(option.MentionType); + if (!string.IsNullOrEmpty(option.EmbedColor)) { - DiscordMentionType.Everyone => "@everyone", - DiscordMentionType.Here => "@here", - _ => string.Empty - }; + data["EmbedColor"] = FormatColorCode(option.EmbedColor); + } + + if (!string.IsNullOrEmpty(option.AvatarUrl)) + { + data["AvatarUrl"] = option.AvatarUrl; + } + + if (!string.IsNullOrEmpty(option.Username)) + { + data["Username"] = option.Username; + data["BotUsername"] = option.Username; + } + + var body = option.GetMessageBody(data); + _logger.LogDebug("SendAsync Body: {@Body}", body); + using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); + using var response = await _httpClientFactory + .CreateClient(NamedClient.Default) + .PostAsync(new Uri(option.WebhookUri), content) + .ConfigureAwait(false); + await response.LogIfFailedAsync(_logger).ConfigureAwait(false); + } + catch (HttpRequestException e) + { + _logger.LogWarning(e, "Error sending notification"); } } + + private static int FormatColorCode(string hexCode) + { + return int.Parse(hexCode[1..6], NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + + private static string GetMentionType(DiscordMentionType mentionType) + { + return mentionType switch + { + DiscordMentionType.Everyone => "@everyone", + DiscordMentionType.Here => "@here", + _ => string.Empty + }; + } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordMentionType.cs b/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordMentionType.cs index cf89c94..5f7ca39 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordMentionType.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordMentionType.cs @@ -1,23 +1,22 @@ -namespace Jellyfin.Plugin.Webhook.Destinations.Discord +namespace Jellyfin.Plugin.Webhook.Destinations.Discord; + +/// +/// Discord mention type. +/// +public enum DiscordMentionType { /// - /// Discord mention type. + /// Mention @everyone. /// - public enum DiscordMentionType - { - /// - /// Mention @everyone. - /// - Everyone = 2, + Everyone = 2, - /// - /// Mention @here. - /// - Here = 1, + /// + /// Mention @here. + /// + Here = 1, - /// - /// Mention none. - /// - None = 0 - } -} \ No newline at end of file + /// + /// Mention none. + /// + None = 0 +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordOption.cs b/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordOption.cs index 7977b54..5dd1321 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordOption.cs @@ -1,28 +1,27 @@ -namespace Jellyfin.Plugin.Webhook.Destinations.Discord +namespace Jellyfin.Plugin.Webhook.Destinations.Discord; + +/// +/// Discord specific options. +/// +public class DiscordOption : BaseOption { /// - /// Discord specific options. + /// Gets or sets the embed color. /// - public class DiscordOption : BaseOption - { - /// - /// Gets or sets the embed color. - /// - public string? EmbedColor { get; set; } + public string? EmbedColor { get; set; } - /// - /// Gets or sets the avatar url. - /// - public string? AvatarUrl { get; set; } + /// + /// Gets or sets the avatar url. + /// + public string? AvatarUrl { get; set; } - /// - /// Gets or sets the bot username. - /// - public string? Username { get; set; } + /// + /// Gets or sets the bot username. + /// + public string? Username { get; set; } - /// - /// Gets or sets the mention type. - /// - public DiscordMentionType MentionType { get; set; } - } -} \ No newline at end of file + /// + /// Gets or sets the mention type. + /// + public DiscordMentionType MentionType { get; set; } +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericClient.cs index d62923f..17a212e 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericClient.cs @@ -9,83 +9,82 @@ using MediaBrowser.Common.Net; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; -namespace Jellyfin.Plugin.Webhook.Destinations.Generic +namespace Jellyfin.Plugin.Webhook.Destinations.Generic; + +/// +/// Client for the . +/// +public class GenericClient : BaseClient, IWebhookClient { + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + /// - /// Client for the . + /// Initializes a new instance of the class. /// - public class GenericClient : BaseClient, IWebhookClient + /// Instance of the . + /// Instance of the interface. + public GenericClient( + IHttpClientFactory httpClientFactory, + ILogger logger) { - private readonly IHttpClientFactory _httpClientFactory; - private readonly ILogger _logger; + _httpClientFactory = httpClientFactory; + _logger = logger; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the . - /// Instance of the interface. - public GenericClient( - IHttpClientFactory httpClientFactory, - ILogger logger) + /// + public async Task SendAsync(GenericOption option, Dictionary data) + { + try { - _httpClientFactory = httpClientFactory; - _logger = logger; + if (!SendWebhook(_logger, option, data)) + { + return; + } + + foreach (var field in option.Fields) + { + if (string.IsNullOrEmpty(field.Key) || string.IsNullOrEmpty(field.Value)) + { + continue; + } + + data[field.Key] = field.Value; + } + + var body = option.GetMessageBody(data); + _logger.LogDebug("SendAsync Body: {@Body}", body); + using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, option.WebhookUri); + var contentType = MediaTypeNames.Text.Plain; + foreach (var header in option.Headers) + { + if (string.IsNullOrEmpty(header.Key) || string.IsNullOrEmpty(header.Value)) + { + continue; + } + + // Content-Type cannot be set manually, must be set on the content. + if (string.Equals(HeaderNames.ContentType, header.Key, StringComparison.OrdinalIgnoreCase) + && !string.IsNullOrEmpty(header.Value)) + { + contentType = header.Value; + } + else + { + httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + } + + httpRequestMessage.Content = new StringContent(body, Encoding.UTF8, contentType); + using var response = await _httpClientFactory + .CreateClient(NamedClient.Default) + .SendAsync(httpRequestMessage) + .ConfigureAwait(false); + await response.LogIfFailedAsync(_logger).ConfigureAwait(false); } - - /// - public async Task SendAsync(GenericOption option, Dictionary data) + catch (HttpRequestException e) { - try - { - if (!SendWebhook(_logger, option, data)) - { - return; - } - - foreach (var field in option.Fields) - { - if (string.IsNullOrEmpty(field.Key) || string.IsNullOrEmpty(field.Value)) - { - continue; - } - - data[field.Key] = field.Value; - } - - var body = option.GetMessageBody(data); - _logger.LogDebug("SendAsync Body: {@Body}", body); - using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, option.WebhookUri); - var contentType = MediaTypeNames.Text.Plain; - foreach (var header in option.Headers) - { - if (string.IsNullOrEmpty(header.Key) || string.IsNullOrEmpty(header.Value)) - { - continue; - } - - // Content-Type cannot be set manually, must be set on the content. - if (string.Equals(HeaderNames.ContentType, header.Key, StringComparison.OrdinalIgnoreCase) - && !string.IsNullOrEmpty(header.Value)) - { - contentType = header.Value; - } - else - { - httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value); - } - } - - httpRequestMessage.Content = new StringContent(body, Encoding.UTF8, contentType); - using var response = await _httpClientFactory - .CreateClient(NamedClient.Default) - .SendAsync(httpRequestMessage) - .ConfigureAwait(false); - await response.LogIfFailedAsync(_logger).ConfigureAwait(false); - } - catch (HttpRequestException e) - { - _logger.LogWarning(e, "Error sending notification"); - } + _logger.LogWarning(e, "Error sending notification"); } } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericOption.cs b/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericOption.cs index 5e11618..acac3ef 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericOption.cs @@ -1,29 +1,28 @@ using System; -namespace Jellyfin.Plugin.Webhook.Destinations.Generic +namespace Jellyfin.Plugin.Webhook.Destinations.Generic; + +/// +/// Generic webhook options. +/// +public class GenericOption : BaseOption { /// - /// Generic webhook options. + /// Initializes a new instance of the class. /// - public class GenericOption : BaseOption + public GenericOption() { - /// - /// Initializes a new instance of the class. - /// - public GenericOption() - { - Headers = Array.Empty(); - Fields = Array.Empty(); - } - - /// - /// Gets or sets the headers. - /// - public GenericOptionValue[] Headers { get; set; } - - /// - /// Gets or sets the fields. - /// - public GenericOptionValue[] Fields { get; set; } + Headers = Array.Empty(); + Fields = Array.Empty(); } -} \ No newline at end of file + + /// + /// Gets or sets the headers. + /// + public GenericOptionValue[] Headers { get; set; } + + /// + /// Gets or sets the fields. + /// + public GenericOptionValue[] Fields { get; set; } +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericOptionValue.cs b/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericOptionValue.cs index bc71d4e..7126db0 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericOptionValue.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericOptionValue.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Plugin.Webhook.Destinations.Generic +namespace Jellyfin.Plugin.Webhook.Destinations.Generic; + +/// +/// Generic option value. +/// +public class GenericOptionValue { /// - /// Generic option value. + /// Gets or sets the option key. /// - public class GenericOptionValue - { - /// - /// Gets or sets the option key. - /// - public string Key { get; set; } = string.Empty; + public string Key { get; set; } = string.Empty; - /// - /// Gets or sets the option value. - /// - public string Value { get; set; } = string.Empty; - } -} \ No newline at end of file + /// + /// Gets or sets the option value. + /// + public string Value { get; set; } = string.Empty; +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormClient.cs b/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormClient.cs index 00de063..1036b81 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormClient.cs @@ -6,80 +6,79 @@ using Jellyfin.Plugin.Webhook.Extensions; using MediaBrowser.Common.Net; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Destinations.GenericForm +namespace Jellyfin.Plugin.Webhook.Destinations.GenericForm; + +/// +/// Client for the . +/// +public class GenericFormClient : BaseClient, IWebhookClient { + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + /// - /// Client for the . + /// Initializes a new instance of the class. /// - public class GenericFormClient : BaseClient, IWebhookClient + /// Instance of the . + /// Instance of the interface. + public GenericFormClient( + IHttpClientFactory httpClientFactory, + ILogger logger) { - private readonly IHttpClientFactory _httpClientFactory; - private readonly ILogger _logger; + _httpClientFactory = httpClientFactory; + _logger = logger; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the . - /// Instance of the interface. - public GenericFormClient( - IHttpClientFactory httpClientFactory, - ILogger logger) + /// + public async Task SendAsync(GenericFormOption option, Dictionary data) + { + try { - _httpClientFactory = httpClientFactory; - _logger = logger; + if (!SendWebhook(_logger, option, data)) + { + return; + } + + foreach (var field in option.Fields) + { + if (string.IsNullOrEmpty(field.Key) || string.IsNullOrEmpty(field.Value)) + { + continue; + } + + data[field.Key] = field.Value; + } + + var body = option.GetMessageBody(data); + var dictionaryBody = JsonSerializer.Deserialize>(body); + if (dictionaryBody is null) + { + _logger.LogWarning("Body is null, unable to send webhook"); + return; + } + + _logger.LogDebug("SendAsync Body: {@Body}", body); + using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, option.WebhookUri); + foreach (var header in option.Headers) + { + if (string.IsNullOrEmpty(header.Key) || string.IsNullOrEmpty(header.Value)) + { + continue; + } + + httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + + httpRequestMessage.Content = new FormUrlEncodedContent(dictionaryBody!); + using var response = await _httpClientFactory + .CreateClient(NamedClient.Default) + .SendAsync(httpRequestMessage) + .ConfigureAwait(false); + await response.LogIfFailedAsync(_logger).ConfigureAwait(false); } - - /// - public async Task SendAsync(GenericFormOption option, Dictionary data) + catch (HttpRequestException e) { - try - { - if (!SendWebhook(_logger, option, data)) - { - return; - } - - foreach (var field in option.Fields) - { - if (string.IsNullOrEmpty(field.Key) || string.IsNullOrEmpty(field.Value)) - { - continue; - } - - data[field.Key] = field.Value; - } - - var body = option.GetMessageBody(data); - var dictionaryBody = JsonSerializer.Deserialize>(body); - if (dictionaryBody is null) - { - _logger.LogWarning("Body is null, unable to send webhook"); - return; - } - - _logger.LogDebug("SendAsync Body: {@Body}", body); - using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, option.WebhookUri); - foreach (var header in option.Headers) - { - if (string.IsNullOrEmpty(header.Key) || string.IsNullOrEmpty(header.Value)) - { - continue; - } - - httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value); - } - - httpRequestMessage.Content = new FormUrlEncodedContent(dictionaryBody!); - using var response = await _httpClientFactory - .CreateClient(NamedClient.Default) - .SendAsync(httpRequestMessage) - .ConfigureAwait(false); - await response.LogIfFailedAsync(_logger).ConfigureAwait(false); - } - catch (HttpRequestException e) - { - _logger.LogWarning(e, "Error sending notification"); - } + _logger.LogWarning(e, "Error sending notification"); } } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormOption.cs b/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormOption.cs index 13c9d71..cf74098 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormOption.cs @@ -1,29 +1,28 @@ using System; -namespace Jellyfin.Plugin.Webhook.Destinations.GenericForm +namespace Jellyfin.Plugin.Webhook.Destinations.GenericForm; + +/// +/// Generic form webhook options. +/// +public class GenericFormOption : BaseOption { /// - /// Generic form webhook options. + /// Initializes a new instance of the class. /// - public class GenericFormOption : BaseOption + public GenericFormOption() { - /// - /// Initializes a new instance of the class. - /// - public GenericFormOption() - { - Headers = Array.Empty(); - Fields = Array.Empty(); - } - - /// - /// Gets or sets the headers. - /// - public GenericFormOptionValue[] Headers { get; set; } - - /// - /// Gets or sets the fields. - /// - public GenericFormOptionValue[] Fields { get; set; } + Headers = Array.Empty(); + Fields = Array.Empty(); } + + /// + /// Gets or sets the headers. + /// + public GenericFormOptionValue[] Headers { get; set; } + + /// + /// Gets or sets the fields. + /// + public GenericFormOptionValue[] Fields { get; set; } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormOptionValue.cs b/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormOptionValue.cs index 2b6fab3..4acf45e 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormOptionValue.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormOptionValue.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Plugin.Webhook.Destinations.GenericForm +namespace Jellyfin.Plugin.Webhook.Destinations.GenericForm; + +/// +/// Generic form option value. +/// +public class GenericFormOptionValue { /// - /// Generic form option value. + /// Gets or sets the option key. /// - public class GenericFormOptionValue - { - /// - /// Gets or sets the option key. - /// - public string Key { get; set; } = string.Empty; + public string Key { get; set; } = string.Empty; - /// - /// Gets or sets the option value. - /// - public string Value { get; set; } = string.Empty; - } + /// + /// Gets or sets the option value. + /// + public string Value { get; set; } = string.Empty; } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyClient.cs index ee13ca7..808a155 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyClient.cs @@ -8,58 +8,57 @@ using Jellyfin.Plugin.Webhook.Extensions; using MediaBrowser.Common.Net; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Destinations.Gotify +namespace Jellyfin.Plugin.Webhook.Destinations.Gotify; + +/// +/// Client for the . +/// +public class GotifyClient : BaseClient, IWebhookClient { + private readonly ILogger _logger; + private readonly IHttpClientFactory _httpClientFactory; + /// - /// Client for the . + /// Initializes a new instance of the class. /// - public class GotifyClient : BaseClient, IWebhookClient + /// Instance of the interface. + /// Instance of the . + public GotifyClient(ILogger logger, IHttpClientFactory httpClientFactory) { - private readonly ILogger _logger; - private readonly IHttpClientFactory _httpClientFactory; + _logger = logger; + _httpClientFactory = httpClientFactory; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the . - public GotifyClient(ILogger logger, IHttpClientFactory httpClientFactory) + /// + public async Task SendAsync(GotifyOption option, Dictionary data) + { + try { - _logger = logger; - _httpClientFactory = httpClientFactory; + if (string.IsNullOrEmpty(option.WebhookUri)) + { + throw new ArgumentException(nameof(option.WebhookUri)); + } + + if (!SendWebhook(_logger, option, data)) + { + return; + } + + // Add gotify specific properties. + data["Priority"] = option.Priority; + + var body = option.GetMessageBody(data); + _logger.LogDebug("SendAsync Body: {@Body}", body); + using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); + using var response = await _httpClientFactory + .CreateClient(NamedClient.Default) + .PostAsync(new Uri(option.WebhookUri.TrimEnd() + $"/message?token={option.Token}"), content) + .ConfigureAwait(false); + await response.LogIfFailedAsync(_logger).ConfigureAwait(false); } - - /// - public async Task SendAsync(GotifyOption option, Dictionary data) + catch (HttpRequestException e) { - try - { - if (string.IsNullOrEmpty(option.WebhookUri)) - { - throw new ArgumentException(nameof(option.WebhookUri)); - } - - if (!SendWebhook(_logger, option, data)) - { - return; - } - - // Add gotify specific properties. - data["Priority"] = option.Priority; - - var body = option.GetMessageBody(data); - _logger.LogDebug("SendAsync Body: {@Body}", body); - using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); - using var response = await _httpClientFactory - .CreateClient(NamedClient.Default) - .PostAsync(new Uri(option.WebhookUri.TrimEnd() + $"/message?token={option.Token}"), content) - .ConfigureAwait(false); - await response.LogIfFailedAsync(_logger).ConfigureAwait(false); - } - catch (HttpRequestException e) - { - _logger.LogWarning(e, "Error sending notification"); - } + _logger.LogWarning(e, "Error sending notification"); } } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyOption.cs b/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyOption.cs index 59c62b3..b477172 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyOption.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Plugin.Webhook.Destinations.Gotify +namespace Jellyfin.Plugin.Webhook.Destinations.Gotify; + +/// +/// Gotify specific options. +/// +public class GotifyOption : BaseOption { /// - /// Gotify specific options. + /// Gets or sets the authentication token. /// - public class GotifyOption : BaseOption - { - /// - /// Gets or sets the authentication token. - /// - public string? Token { get; set; } + public string? Token { get; set; } - /// - /// Gets or sets the notification priority. - /// - public int Priority { get; set; } - } -} \ No newline at end of file + /// + /// Gets or sets the notification priority. + /// + public int Priority { get; set; } +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/IWebhookClient.cs b/Jellyfin.Plugin.Webhook/Destinations/IWebhookClient.cs index 6be3d16..e5c5bcc 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/IWebhookClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/IWebhookClient.cs @@ -1,21 +1,20 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace Jellyfin.Plugin.Webhook.Destinations +namespace Jellyfin.Plugin.Webhook.Destinations; + +/// +/// Destination interface. +/// +/// The type of options. +public interface IWebhookClient + where TDestinationOption : BaseOption { /// - /// Destination interface. + /// Send message to destination. /// - /// The type of options. - public interface IWebhookClient - where TDestinationOption : BaseOption - { - /// - /// Send message to destination. - /// - /// The destination option. - /// The message to send. - /// A representing the asynchronous operation. - Task SendAsync(TDestinationOption option, Dictionary data); - } + /// The destination option. + /// The message to send. + /// A representing the asynchronous operation. + Task SendAsync(TDestinationOption option, Dictionary data); } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/IMqttClients.cs b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/IMqttClients.cs index 6a0987f..be28c59 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/IMqttClients.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/IMqttClients.cs @@ -22,4 +22,4 @@ public interface IMqttClients /// guid of MqttOption. /// Instance of the interface. IManagedMqttClient? GetClient(Guid guid); -} \ No newline at end of file +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClient.cs index c628c62..17e5d98 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClient.cs @@ -52,4 +52,4 @@ public class MqttClient : BaseClient, IWebhookClient _logger.LogDebug(e, "Error sending MQTT notification"); } } -} \ No newline at end of file +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClients.cs b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClients.cs index 32e7b14..6da8d51 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClients.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClients.cs @@ -131,4 +131,4 @@ public class MqttClients : IMqttClients, IDisposable client.Dispose(); } } -} \ No newline at end of file +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttOption.cs b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttOption.cs index f5c1297..adb1c8c 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttOption.cs @@ -70,4 +70,4 @@ public class MqttOption : BaseOption /// /// The compiled handlebars subject template. public HandlebarsTemplate GetCompiledTopicTemplate() => _compiledTopicTemplate ??= Handlebars.Compile(HandlebarsFunctionHelpers.Base64Decode(Topic)); -} \ No newline at end of file +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs b/Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs index 15b1024..e1cefb8 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/NotificationType.cs @@ -1,128 +1,127 @@ -namespace Jellyfin.Plugin.Webhook.Destinations +namespace Jellyfin.Plugin.Webhook.Destinations; + +/// +/// The type of notification. +/// +public enum NotificationType { /// - /// The type of notification. + /// No notification type. /// - public enum NotificationType - { - /// - /// No notification type. - /// - None = 0, + None = 0, - /// - /// Item added notification. - /// - ItemAdded = 1, + /// + /// Item added notification. + /// + ItemAdded = 1, - /// - /// Generic notification. - /// - Generic = 2, + /// + /// Generic notification. + /// + Generic = 2, - /// - /// Playback start notification. - /// - PlaybackStart = 3, + /// + /// Playback start notification. + /// + PlaybackStart = 3, - /// - /// Playback progress notification. - /// - PlaybackProgress = 4, + /// + /// Playback progress notification. + /// + PlaybackProgress = 4, - /// - /// Playback stop notification. - /// - PlaybackStop = 5, + /// + /// Playback stop notification. + /// + PlaybackStop = 5, - /// - /// Subtitle download failure. - /// - SubtitleDownloadFailure = 6, + /// + /// Subtitle download failure. + /// + SubtitleDownloadFailure = 6, - /// - /// Authentication failure. - /// - AuthenticationFailure = 7, + /// + /// Authentication failure. + /// + AuthenticationFailure = 7, - /// - /// Authentication success. - /// - AuthenticationSuccess = 8, + /// + /// Authentication success. + /// + AuthenticationSuccess = 8, - /// - /// Session started. - /// - SessionStart = 9, + /// + /// Session started. + /// + SessionStart = 9, - /// - /// Server pending restart. - /// - PendingRestart = 10, + /// + /// Server pending restart. + /// + PendingRestart = 10, - /// - /// Task completed. - /// - TaskCompleted = 11, + /// + /// Task completed. + /// + TaskCompleted = 11, - /// - /// Plugin installation cancelled. - /// - PluginInstallationCancelled = 12, + /// + /// Plugin installation cancelled. + /// + PluginInstallationCancelled = 12, - /// - /// Plugin installation failed. - /// - PluginInstallationFailed = 13, + /// + /// Plugin installation failed. + /// + PluginInstallationFailed = 13, - /// - /// Plugin installed. - /// - PluginInstalled = 14, + /// + /// Plugin installed. + /// + PluginInstalled = 14, - /// - /// Plugin installing. - /// - PluginInstalling = 15, + /// + /// Plugin installing. + /// + PluginInstalling = 15, - /// - /// Plugin uninstalled. - /// - PluginUninstalled = 16, + /// + /// Plugin uninstalled. + /// + PluginUninstalled = 16, - /// - /// Plugin updated. - /// - PluginUpdated = 17, + /// + /// Plugin updated. + /// + PluginUpdated = 17, - /// - /// User created. - /// - UserCreated = 18, + /// + /// User created. + /// + UserCreated = 18, - /// - /// User created. - /// - UserDeleted = 19, + /// + /// User created. + /// + UserDeleted = 19, - /// - /// User locked out. - /// - UserLockedOut = 20, + /// + /// User locked out. + /// + UserLockedOut = 20, - /// - /// User password changed. - /// - UserPasswordChanged = 21, + /// + /// User password changed. + /// + UserPasswordChanged = 21, - /// - /// User updated. - /// - UserUpdated = 22, + /// + /// User updated. + /// + UserUpdated = 22, - /// - /// User data saved. - /// - UserDataSaved = 23 - } + /// + /// User data saved. + /// + UserDataSaved = 23 } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletClient.cs index 2f1a00b..b1e79a4 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletClient.cs @@ -7,60 +7,59 @@ using Jellyfin.Plugin.Webhook.Extensions; using MediaBrowser.Common.Net; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Destinations.Pushbullet +namespace Jellyfin.Plugin.Webhook.Destinations.Pushbullet; + +/// +/// Client for the . +/// +public class PushbulletClient : BaseClient, IWebhookClient { + private readonly ILogger _logger; + private readonly IHttpClientFactory _httpClientFactory; + /// - /// Client for the . + /// Initializes a new instance of the class. /// - public class PushbulletClient : BaseClient, IWebhookClient + /// Instance of the interface. + /// Instance of the interface. + public PushbulletClient( + ILogger logger, + IHttpClientFactory httpClientFactory) { - private readonly ILogger _logger; - private readonly IHttpClientFactory _httpClientFactory; + _logger = logger; + _httpClientFactory = httpClientFactory; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PushbulletClient( - ILogger logger, - IHttpClientFactory httpClientFactory) + /// + public async Task SendAsync(PushbulletOption option, Dictionary data) + { + try { - _logger = logger; - _httpClientFactory = httpClientFactory; + if (!SendWebhook(_logger, option, data)) + { + return; + } + + data["PushbulletToken"] = option.Token; + data["PushbulletDeviceId"] = option.DeviceId; + data["PushbulletChannel"] = option.Channel; + + var body = option.GetMessageBody(data); + _logger.LogDebug("SendAsync Body: {@Body}", body); + + using var requestOptions = new HttpRequestMessage(HttpMethod.Post, string.IsNullOrEmpty(option.WebhookUri) ? PushbulletOption.ApiUrl : option.WebhookUri); + requestOptions.Headers.TryAddWithoutValidation("Access-Token", option.Token); + requestOptions.Content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); + + using var response = await _httpClientFactory + .CreateClient(NamedClient.Default) + .SendAsync(requestOptions) + .ConfigureAwait(false); + await response.LogIfFailedAsync(_logger).ConfigureAwait(false); } - - /// - public async Task SendAsync(PushbulletOption option, Dictionary data) + catch (HttpRequestException e) { - try - { - if (!SendWebhook(_logger, option, data)) - { - return; - } - - data["PushbulletToken"] = option.Token; - data["PushbulletDeviceId"] = option.DeviceId; - data["PushbulletChannel"] = option.Channel; - - var body = option.GetMessageBody(data); - _logger.LogDebug("SendAsync Body: {@Body}", body); - - using var requestOptions = new HttpRequestMessage(HttpMethod.Post, string.IsNullOrEmpty(option.WebhookUri) ? PushbulletOption.ApiUrl : option.WebhookUri); - requestOptions.Headers.TryAddWithoutValidation("Access-Token", option.Token); - requestOptions.Content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); - - using var response = await _httpClientFactory - .CreateClient(NamedClient.Default) - .SendAsync(requestOptions) - .ConfigureAwait(false); - await response.LogIfFailedAsync(_logger).ConfigureAwait(false); - } - catch (HttpRequestException e) - { - _logger.LogWarning(e, "Error sending notification"); - } + _logger.LogWarning(e, "Error sending notification"); } } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletOption.cs b/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletOption.cs index b2e8368..88b65e1 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletOption.cs @@ -1,31 +1,30 @@ using System.Text.Json.Serialization; -namespace Jellyfin.Plugin.Webhook.Destinations.Pushbullet +namespace Jellyfin.Plugin.Webhook.Destinations.Pushbullet; + +/// +/// Pushbullet specific option. +/// +public class PushbulletOption : BaseOption { /// - /// Pushbullet specific option. + /// The webhook endpoint. /// - public class PushbulletOption : BaseOption - { - /// - /// The webhook endpoint. - /// - [JsonIgnore] - public const string ApiUrl = "https://api.pushbullet.com/v2/pushes"; + [JsonIgnore] + public const string ApiUrl = "https://api.pushbullet.com/v2/pushes"; - /// - /// Gets or sets the pushbullet token. - /// - public string Token { get; set; } = string.Empty; + /// + /// Gets or sets the pushbullet token. + /// + public string Token { get; set; } = string.Empty; - /// - /// Gets or sets the device id. - /// - public string DeviceId { get; set; } = string.Empty; + /// + /// Gets or sets the device id. + /// + public string DeviceId { get; set; } = string.Empty; - /// - /// Gets or sets the channel. - /// - public string Channel { get; set; } = string.Empty; - } -} \ No newline at end of file + /// + /// Gets or sets the channel. + /// + public string Channel { get; set; } = string.Empty; +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverClient.cs index 9a04dbe..e6b7ffd 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverClient.cs @@ -8,82 +8,81 @@ using Jellyfin.Plugin.Webhook.Extensions; using MediaBrowser.Common.Net; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Destinations.Pushover +namespace Jellyfin.Plugin.Webhook.Destinations.Pushover; + +/// +/// Client for the . +/// +public class PushoverClient : BaseClient, IWebhookClient { + private readonly ILogger _logger; + private readonly IHttpClientFactory _httpClientFactory; + /// - /// Client for the . + /// Initializes a new instance of the class. /// - public class PushoverClient : BaseClient, IWebhookClient + /// Instance of the interface. + /// Instance of the . + public PushoverClient(ILogger logger, IHttpClientFactory httpClientFactory) { - private readonly ILogger _logger; - private readonly IHttpClientFactory _httpClientFactory; + _logger = logger; + _httpClientFactory = httpClientFactory; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the . - public PushoverClient(ILogger logger, IHttpClientFactory httpClientFactory) + /// + public async Task SendAsync(PushoverOption option, Dictionary data) + { + try { - _logger = logger; - _httpClientFactory = httpClientFactory; + if (!SendWebhook(_logger, option, data)) + { + return; + } + + data["Token"] = option.Token; + data["UserToken"] = option.UserToken; + if (!string.IsNullOrEmpty(option.Device)) + { + data["Device"] = option.Device; + } + + if (!string.IsNullOrEmpty(option.Title)) + { + data["Title"] = option.Title; + } + + if (!string.IsNullOrEmpty(option.MessageUrl)) + { + data["MessageUrl"] = option.MessageUrl; + } + + if (!string.IsNullOrEmpty(option.MessageUrlTitle)) + { + data["MessageUrlTitle"] = option.MessageUrlTitle; + } + + if (option.MessagePriority is not null) + { + data["MessagePriority"] = option.MessagePriority; + } + + if (!string.IsNullOrEmpty(option.NotificationSound)) + { + data["NotificationSound"] = option.NotificationSound; + } + + var body = option.GetMessageBody(data); + _logger.LogDebug("SendAsync Body: {@Body}", body); + using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); + using var response = await _httpClientFactory + .CreateClient(NamedClient.Default) + .PostAsync(string.IsNullOrEmpty(option.WebhookUri) ? PushoverOption.ApiUrl : new Uri(option.WebhookUri), content) + .ConfigureAwait(false); + await response.LogIfFailedAsync(_logger).ConfigureAwait(false); } - - /// - public async Task SendAsync(PushoverOption option, Dictionary data) + catch (HttpRequestException e) { - try - { - if (!SendWebhook(_logger, option, data)) - { - return; - } - - data["Token"] = option.Token; - data["UserToken"] = option.UserToken; - if (!string.IsNullOrEmpty(option.Device)) - { - data["Device"] = option.Device; - } - - if (!string.IsNullOrEmpty(option.Title)) - { - data["Title"] = option.Title; - } - - if (!string.IsNullOrEmpty(option.MessageUrl)) - { - data["MessageUrl"] = option.MessageUrl; - } - - if (!string.IsNullOrEmpty(option.MessageUrlTitle)) - { - data["MessageUrlTitle"] = option.MessageUrlTitle; - } - - if (option.MessagePriority is not null) - { - data["MessagePriority"] = option.MessagePriority; - } - - if (!string.IsNullOrEmpty(option.NotificationSound)) - { - data["NotificationSound"] = option.NotificationSound; - } - - var body = option.GetMessageBody(data); - _logger.LogDebug("SendAsync Body: {@Body}", body); - using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); - using var response = await _httpClientFactory - .CreateClient(NamedClient.Default) - .PostAsync(string.IsNullOrEmpty(option.WebhookUri) ? PushoverOption.ApiUrl : new Uri(option.WebhookUri), content) - .ConfigureAwait(false); - await response.LogIfFailedAsync(_logger).ConfigureAwait(false); - } - catch (HttpRequestException e) - { - _logger.LogWarning(e, "Error sending notification"); - } + _logger.LogWarning(e, "Error sending notification"); } } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverOption.cs b/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverOption.cs index 83020eb..20ebc52 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverOption.cs @@ -1,57 +1,56 @@ using System; using System.Text.Json.Serialization; -namespace Jellyfin.Plugin.Webhook.Destinations.Pushover +namespace Jellyfin.Plugin.Webhook.Destinations.Pushover; + +/// +/// Pushover specific options. +/// +public class PushoverOption : BaseOption { /// - /// Pushover specific options. + /// The webhook endpoint. /// - public class PushoverOption : BaseOption - { - /// - /// The webhook endpoint. - /// - [JsonIgnore] - public static readonly Uri ApiUrl = new Uri("https://api.pushover.net/1/messages.json"); + [JsonIgnore] + public static readonly Uri ApiUrl = new Uri("https://api.pushover.net/1/messages.json"); - /// - /// Gets or sets the pushover token. - /// - public string Token { get; set; } = string.Empty; + /// + /// Gets or sets the pushover token. + /// + public string Token { get; set; } = string.Empty; - /// - /// Gets or sets the pushover user token. - /// - public string UserToken { get; set; } = string.Empty; + /// + /// Gets or sets the pushover user token. + /// + public string UserToken { get; set; } = string.Empty; - /// - /// Gets or sets the device. - /// - public string? Device { get; set; } + /// + /// Gets or sets the device. + /// + public string? Device { get; set; } - /// - /// Gets or sets the message title. - /// - public string? Title { get; set; } + /// + /// Gets or sets the message title. + /// + public string? Title { get; set; } - /// - /// Gets or sets the message url. - /// - public string? MessageUrl { get; set; } + /// + /// Gets or sets the message url. + /// + public string? MessageUrl { get; set; } - /// - /// Gets or sets the message url title. - /// - public string? MessageUrlTitle { get; set; } + /// + /// Gets or sets the message url title. + /// + public string? MessageUrlTitle { get; set; } - /// - /// Gets or sets the message priority. - /// - public int? MessagePriority { get; set; } + /// + /// Gets or sets the message priority. + /// + public int? MessagePriority { get; set; } - /// - /// Gets or sets the notification sound. - /// - public string? NotificationSound { get; set; } - } -} \ No newline at end of file + /// + /// Gets or sets the notification sound. + /// + public string? NotificationSound { get; set; } +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackClient.cs index 37d7d66..2b505a1 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackClient.cs @@ -8,59 +8,58 @@ using Jellyfin.Plugin.Webhook.Extensions; using MediaBrowser.Common.Net; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Destinations.Slack +namespace Jellyfin.Plugin.Webhook.Destinations.Slack; + +/// +/// Client for the . +/// +public class SlackClient : BaseClient, IWebhookClient { + private readonly ILogger _logger; + private readonly IHttpClientFactory _httpClientFactory; + /// - /// Client for the . + /// Initializes a new instance of the class. /// - public class SlackClient : BaseClient, IWebhookClient + /// Instance of the interface. + /// Instance of the . + public SlackClient(ILogger logger, IHttpClientFactory httpClientFactory) { - private readonly ILogger _logger; - private readonly IHttpClientFactory _httpClientFactory; + _logger = logger; + _httpClientFactory = httpClientFactory; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the . - public SlackClient(ILogger logger, IHttpClientFactory httpClientFactory) + /// + public async Task SendAsync(SlackOption option, Dictionary data) + { + try { - _logger = logger; - _httpClientFactory = httpClientFactory; + if (string.IsNullOrEmpty(option.WebhookUri)) + { + throw new ArgumentException(nameof(option.WebhookUri)); + } + + if (!SendWebhook(_logger, option, data)) + { + return; + } + + data["SlackUsername"] = option.Username; + data["BotUsername"] = option.Username; + data["SlackIconUrl"] = option.IconUrl; + + var body = option.GetMessageBody(data); + _logger.LogDebug("SendAsync Body: {@Body}", body); + using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); + using var response = await _httpClientFactory + .CreateClient(NamedClient.Default) + .PostAsync(new Uri(option.WebhookUri), content) + .ConfigureAwait(false); + await response.LogIfFailedAsync(_logger).ConfigureAwait(false); } - - /// - public async Task SendAsync(SlackOption option, Dictionary data) + catch (HttpRequestException e) { - try - { - if (string.IsNullOrEmpty(option.WebhookUri)) - { - throw new ArgumentException(nameof(option.WebhookUri)); - } - - if (!SendWebhook(_logger, option, data)) - { - return; - } - - data["SlackUsername"] = option.Username; - data["BotUsername"] = option.Username; - data["SlackIconUrl"] = option.IconUrl; - - var body = option.GetMessageBody(data); - _logger.LogDebug("SendAsync Body: {@Body}", body); - using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); - using var response = await _httpClientFactory - .CreateClient(NamedClient.Default) - .PostAsync(new Uri(option.WebhookUri), content) - .ConfigureAwait(false); - await response.LogIfFailedAsync(_logger).ConfigureAwait(false); - } - catch (HttpRequestException e) - { - _logger.LogWarning(e, "Error sending notification"); - } + _logger.LogWarning(e, "Error sending notification"); } } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackOption.cs b/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackOption.cs index 41ccd81..13dadc3 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackOption.cs @@ -1,18 +1,17 @@ -namespace Jellyfin.Plugin.Webhook.Destinations.Slack +namespace Jellyfin.Plugin.Webhook.Destinations.Slack; + +/// +/// Slack specific options. +/// +public class SlackOption : BaseOption { /// - /// Slack specific options. + /// Gets or sets the username. /// - public class SlackOption : BaseOption - { - /// - /// Gets or sets the username. - /// - public string Username { get; set; } = string.Empty; + public string Username { get; set; } = string.Empty; - /// - /// Gets or sets the icon url. - /// - public string IconUrl { get; set; } = string.Empty; - } -} \ No newline at end of file + /// + /// Gets or sets the icon url. + /// + public string IconUrl { get; set; } = string.Empty; +} diff --git a/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs index 9790988..190e6e6 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs @@ -4,60 +4,59 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using MimeKit; -namespace Jellyfin.Plugin.Webhook.Destinations.Smtp +namespace Jellyfin.Plugin.Webhook.Destinations.Smtp; + +/// +/// Client for the . +/// +public class SmtpClient : BaseClient, IWebhookClient { + private readonly ILogger _logger; + /// - /// Client for the . + /// Initializes a new instance of the class. /// - public class SmtpClient : BaseClient, IWebhookClient + /// Instance of the interface. + public SmtpClient(ILogger logger) { - private readonly ILogger _logger; + _logger = logger; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - public SmtpClient(ILogger logger) + /// + public async Task SendAsync(SmtpOption option, Dictionary data) + { + try { - _logger = logger; + if (!SendWebhook(_logger, option, data)) + { + return; + } + + var message = new MimeMessage(); + message.From.Add(new MailboxAddress(option.SenderAddress, option.SenderAddress)); + message.To.Add(new MailboxAddress(option.ReceiverAddress, option.ReceiverAddress)); + + message.Subject = option.GetCompiledSubjectTemplate()(data); + message.Body = new TextPart(option.IsHtml ? "html" : "plain") + { + Text = option.GetMessageBody(data) + }; + + using var smtpClient = new MailKit.Net.Smtp.SmtpClient(); + await smtpClient.ConnectAsync(option.SmtpServer, option.SmtpPort, option.UseSsl) + .ConfigureAwait(false); + if (option.UseCredentials) + { + await smtpClient.AuthenticateAsync(option.Username, option.Password) + .ConfigureAwait(false); + } + + await smtpClient.SendAsync(message) + .ConfigureAwait(false); } - - /// - public async Task SendAsync(SmtpOption option, Dictionary data) + catch (Exception e) { - try - { - if (!SendWebhook(_logger, option, data)) - { - return; - } - - var message = new MimeMessage(); - message.From.Add(new MailboxAddress(option.SenderAddress, option.SenderAddress)); - message.To.Add(new MailboxAddress(option.ReceiverAddress, option.ReceiverAddress)); - - message.Subject = option.GetCompiledSubjectTemplate()(data); - message.Body = new TextPart(option.IsHtml ? "html" : "plain") - { - Text = option.GetMessageBody(data) - }; - - using var smtpClient = new MailKit.Net.Smtp.SmtpClient(); - await smtpClient.ConnectAsync(option.SmtpServer, option.SmtpPort, option.UseSsl) - .ConfigureAwait(false); - if (option.UseCredentials) - { - await smtpClient.AuthenticateAsync(option.Username, option.Password) - .ConfigureAwait(false); - } - - await smtpClient.SendAsync(message) - .ConfigureAwait(false); - } - catch (Exception e) - { - _logger.LogWarning(e, "Error sending email"); - } + _logger.LogWarning(e, "Error sending email"); } } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpOption.cs b/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpOption.cs index 7f8c26a..c0f2cfe 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpOption.cs @@ -1,72 +1,71 @@ using HandlebarsDotNet; using Jellyfin.Plugin.Webhook.Helpers; -namespace Jellyfin.Plugin.Webhook.Destinations.Smtp +namespace Jellyfin.Plugin.Webhook.Destinations.Smtp; + +/// +/// Smtp specific option. +/// +public class SmtpOption : BaseOption { + private HandlebarsTemplate? _compiledSubjectTemplate; + /// - /// Smtp specific option. + /// Gets or sets the sender address. /// - public class SmtpOption : BaseOption + public string SenderAddress { get; set; } = string.Empty; + + /// + /// Gets or sets the receiver address. + /// + public string ReceiverAddress { get; set; } = string.Empty; + + /// + /// Gets or sets the smtp server. + /// + public string SmtpServer { get; set; } = string.Empty; + + /// + /// Gets or sets the smtp port. + /// + public int SmtpPort { get; set; } = 25; + + /// + /// Gets or sets a value indicating whether use credentials. + /// + public bool UseCredentials { get; set; } + + /// + /// Gets or sets the username. + /// + public string Username { get; set; } = string.Empty; + + /// + /// Gets or sets the password. + /// + public string Password { get; set; } = string.Empty; + + /// + /// Gets or sets a value indicating whether to use ssl. + /// + public bool UseSsl { get; set; } + + /// + /// Gets or sets a value indicating whether the body is html. + /// + public bool IsHtml { get; set; } + + /// + /// Gets or sets the email subject template. + /// + public string SubjectTemplate { get; set; } = string.Empty; + + /// + /// Gets the compiled handlebars subject template. + /// + /// The compiled handlebars subject template. + public HandlebarsTemplate GetCompiledSubjectTemplate() { - private HandlebarsTemplate? _compiledSubjectTemplate; - - /// - /// Gets or sets the sender address. - /// - public string SenderAddress { get; set; } = string.Empty; - - /// - /// Gets or sets the receiver address. - /// - public string ReceiverAddress { get; set; } = string.Empty; - - /// - /// Gets or sets the smtp server. - /// - public string SmtpServer { get; set; } = string.Empty; - - /// - /// Gets or sets the smtp port. - /// - public int SmtpPort { get; set; } = 25; - - /// - /// Gets or sets a value indicating whether use credentials. - /// - public bool UseCredentials { get; set; } - - /// - /// Gets or sets the username. - /// - public string Username { get; set; } = string.Empty; - - /// - /// Gets or sets the password. - /// - public string Password { get; set; } = string.Empty; - - /// - /// Gets or sets a value indicating whether to use ssl. - /// - public bool UseSsl { get; set; } - - /// - /// Gets or sets a value indicating whether the body is html. - /// - public bool IsHtml { get; set; } - - /// - /// Gets or sets the email subject template. - /// - public string SubjectTemplate { get; set; } = string.Empty; - - /// - /// Gets the compiled handlebars subject template. - /// - /// The compiled handlebars subject template. - public HandlebarsTemplate GetCompiledSubjectTemplate() - { - return _compiledSubjectTemplate ??= Handlebars.Compile(HandlebarsFunctionHelpers.Base64Decode(SubjectTemplate)); - } + return _compiledSubjectTemplate ??= Handlebars.Compile(HandlebarsFunctionHelpers.Base64Decode(SubjectTemplate)); } -} \ No newline at end of file +} diff --git a/Jellyfin.Plugin.Webhook/Extensions/HttpResponseMessageExtensions.cs b/Jellyfin.Plugin.Webhook/Extensions/HttpResponseMessageExtensions.cs index c415ced..71e19a8 100644 --- a/Jellyfin.Plugin.Webhook/Extensions/HttpResponseMessageExtensions.cs +++ b/Jellyfin.Plugin.Webhook/Extensions/HttpResponseMessageExtensions.cs @@ -2,40 +2,39 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Extensions +namespace Jellyfin.Plugin.Webhook.Extensions; + +/// +/// Extension methods for . +/// +public static class HttpResponseMessageExtensions { /// - /// Extension methods for . + /// Log a warning message if the contains an error status code. /// - public static class HttpResponseMessageExtensions + /// The HTTP response to log if failed. + /// The logger to use to log the warning. + /// A task representing the async operation. + public static async Task LogIfFailedAsync(this HttpResponseMessage response, ILogger logger) { - /// - /// Log a warning message if the contains an error status code. - /// - /// The HTTP response to log if failed. - /// The logger to use to log the warning. - /// A task representing the async operation. - public static async Task LogIfFailedAsync(this HttpResponseMessage response, ILogger logger) + // Don't log anything for successful responses + if (response.IsSuccessStatusCode) { - // Don't log anything for successful responses - if (response.IsSuccessStatusCode) - { - return; - } - - // Log the request that caused the failed response, if available - var request = response.RequestMessage; - if (request is not null) - { - var requestStr = request.Content is not null - ? await request.Content.ReadAsStringAsync().ConfigureAwait(false) - : ""; - logger.LogWarning("Notification failed with {Method} request to {Url}: {Content}", request.Method, request.RequestUri, requestStr); - } - - // Log the response - var responseStr = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - logger.LogWarning("Notification failed with response status code {StatusCode}: {Content}", response.StatusCode, responseStr); + return; } + + // Log the request that caused the failed response, if available + var request = response.RequestMessage; + if (request is not null) + { + var requestStr = request.Content is not null + ? await request.Content.ReadAsStringAsync().ConfigureAwait(false) + : ""; + logger.LogWarning("Notification failed with {Method} request to {Url}: {Content}", request.Method, request.RequestUri, requestStr); + } + + // Log the response + var responseStr = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + logger.LogWarning("Notification failed with response status code {StatusCode}: {Content}", response.StatusCode, responseStr); } } diff --git a/Jellyfin.Plugin.Webhook/Helpers/DataObjectHelpers.cs b/Jellyfin.Plugin.Webhook/Helpers/DataObjectHelpers.cs index 02a1e65..282497e 100644 --- a/Jellyfin.Plugin.Webhook/Helpers/DataObjectHelpers.cs +++ b/Jellyfin.Plugin.Webhook/Helpers/DataObjectHelpers.cs @@ -13,349 +13,348 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Updates; -namespace Jellyfin.Plugin.Webhook.Helpers +namespace Jellyfin.Plugin.Webhook.Helpers; + +/// +/// Data object helpers. +/// +public static class DataObjectHelpers { /// - /// Data object helpers. + /// Gets the default data object. /// - public static class DataObjectHelpers + /// Instance of the interface. + /// The notification type. + /// The default data object. + public static Dictionary GetBaseDataObject(IServerApplicationHost applicationHost, NotificationType notificationType) { - /// - /// Gets the default data object. - /// - /// Instance of the interface. - /// The notification type. - /// The default data object. - public static Dictionary GetBaseDataObject(IServerApplicationHost applicationHost, NotificationType notificationType) - { - var dataObject = new Dictionary(StringComparer.OrdinalIgnoreCase); - dataObject["ServerId"] = applicationHost.SystemId; - dataObject["ServerName"] = applicationHost.FriendlyName.Escape(); - dataObject["ServerVersion"] = applicationHost.ApplicationVersionString; - dataObject["ServerUrl"] = WebhookPlugin.Instance?.Configuration.ServerUrl ?? "localhost:8096"; - dataObject[nameof(NotificationType)] = notificationType.ToString(); + var dataObject = new Dictionary(StringComparer.OrdinalIgnoreCase); + dataObject["ServerId"] = applicationHost.SystemId; + dataObject["ServerName"] = applicationHost.FriendlyName.Escape(); + dataObject["ServerVersion"] = applicationHost.ApplicationVersionString; + dataObject["ServerUrl"] = WebhookPlugin.Instance?.Configuration.ServerUrl ?? "localhost:8096"; + dataObject[nameof(NotificationType)] = notificationType.ToString(); + return dataObject; + } + + /// + /// Get data object from . + /// + /// The existing data object. + /// Instance of the . + /// The data object. + public static Dictionary AddBaseItemData(this Dictionary dataObject, BaseItem? item) + { + if (item is null) + { return dataObject; } - /// - /// Get data object from . - /// - /// The existing data object. - /// Instance of the . - /// The data object. - public static Dictionary AddBaseItemData(this Dictionary dataObject, BaseItem? item) + dataObject["Timestamp"] = DateTime.Now; + dataObject["UtcTimestamp"] = DateTime.UtcNow; + dataObject["Name"] = item.Name.Escape(); + dataObject["Overview"] = item.Overview.Escape(); + dataObject["Tagline"] = item.Tagline.Escape(); + dataObject["ItemId"] = item.Id; + dataObject["ItemType"] = item.GetType().Name.Escape(); + dataObject["RunTimeTicks"] = item.RunTimeTicks ?? 0; + dataObject["RunTime"] = TimeSpan.FromTicks(item.RunTimeTicks ?? 0).ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture); + + if (item.ProductionYear is not null) { - if (item is null) - { - return dataObject; - } + dataObject["Year"] = item.ProductionYear; + } - dataObject["Timestamp"] = DateTime.Now; - dataObject["UtcTimestamp"] = DateTime.UtcNow; - dataObject["Name"] = item.Name.Escape(); - dataObject["Overview"] = item.Overview.Escape(); - dataObject["Tagline"] = item.Tagline.Escape(); - dataObject["ItemId"] = item.Id; - dataObject["ItemType"] = item.GetType().Name.Escape(); - dataObject["RunTimeTicks"] = item.RunTimeTicks ?? 0; - dataObject["RunTime"] = TimeSpan.FromTicks(item.RunTimeTicks ?? 0).ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture); - - if (item.ProductionYear is not null) - { - dataObject["Year"] = item.ProductionYear; - } - - switch (item) - { - case Season season: - if (!string.IsNullOrEmpty(season.Series?.Name)) - { - dataObject["SeriesName"] = season.Series.Name.Escape(); - } - - if (season.Series?.ProductionYear is not null) - { - dataObject["Year"] = season.Series.ProductionYear; - } - - if (season.IndexNumber is not null) - { - dataObject["SeasonNumber"] = season.IndexNumber; - dataObject["SeasonNumber00"] = season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); - dataObject["SeasonNumber000"] = season.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture); - } - - break; - case Episode episode: - if (!string.IsNullOrEmpty(episode.Series?.Name)) - { - dataObject["SeriesName"] = episode.Series.Name.Escape(); - } - - if (episode.Season?.IndexNumber is not null) - { - dataObject["SeasonNumber"] = episode.Season.IndexNumber; - dataObject["SeasonNumber00"] = episode.Season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); - dataObject["SeasonNumber000"] = episode.Season.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture); - } - - if (episode.IndexNumber is not null) - { - dataObject["EpisodeNumber"] = episode.IndexNumber; - dataObject["EpisodeNumber00"] = episode.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); - dataObject["EpisodeNumber000"] = episode.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture); - } - - if (episode.IndexNumberEnd is not null) - { - dataObject["EpisodeNumberEnd"] = episode.IndexNumberEnd; - dataObject["EpisodeNumberEnd00"] = episode.IndexNumberEnd.Value.ToString("00", CultureInfo.InvariantCulture); - dataObject["EpisodeNumberEnd000"] = episode.IndexNumberEnd.Value.ToString("000", CultureInfo.InvariantCulture); - } - - if (episode.Series?.ProductionYear is not null) - { - dataObject["Year"] = episode.Series.ProductionYear; - } - - break; - case Audio audio: - if (!string.IsNullOrEmpty(audio.Album)) - { - dataObject["Album"] = audio.Album; - } - - if (audio.Artists.Count != 0) - { - // Should all artists be sent? - dataObject["Artist"] = audio.Artists[0]; - } - - if (audio.ProductionYear is not null) - { - dataObject["Year"] = audio.ProductionYear; - } - - break; - - case MusicAlbum album: - if (album.Artists.Count != 0) - { - // Should all artists be sent? - dataObject["Artist"] = album.Artists[0]; - } - - if (album.ProductionYear is not null) - { - dataObject["Year"] = album.ProductionYear; - } - - break; - } - - foreach (var (providerKey, providerValue) in item.ProviderIds) - { - dataObject[$"Provider_{providerKey.ToLowerInvariant()}"] = providerValue; - } - - var itemMediaStreams = item.GetMediaStreams(); - if (itemMediaStreams is not null) - { - var streamCounter = new Dictionary(); - foreach (var mediaStream in itemMediaStreams) + switch (item) + { + case Season season: + if (!string.IsNullOrEmpty(season.Series?.Name)) { - streamCounter.TryGetValue(mediaStream.Type, out var count); - streamCounter[mediaStream.Type] = count + 1; - var baseKey = $"{mediaStream.Type}_{count}"; + dataObject["SeriesName"] = season.Series.Name.Escape(); + } - switch (mediaStream.Type) + if (season.Series?.ProductionYear is not null) + { + dataObject["Year"] = season.Series.ProductionYear; + } + + if (season.IndexNumber is not null) + { + dataObject["SeasonNumber"] = season.IndexNumber; + dataObject["SeasonNumber00"] = season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); + dataObject["SeasonNumber000"] = season.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture); + } + + break; + case Episode episode: + if (!string.IsNullOrEmpty(episode.Series?.Name)) + { + dataObject["SeriesName"] = episode.Series.Name.Escape(); + } + + if (episode.Season?.IndexNumber is not null) + { + dataObject["SeasonNumber"] = episode.Season.IndexNumber; + dataObject["SeasonNumber00"] = episode.Season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); + dataObject["SeasonNumber000"] = episode.Season.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture); + } + + if (episode.IndexNumber is not null) + { + dataObject["EpisodeNumber"] = episode.IndexNumber; + dataObject["EpisodeNumber00"] = episode.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture); + dataObject["EpisodeNumber000"] = episode.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture); + } + + if (episode.IndexNumberEnd is not null) + { + dataObject["EpisodeNumberEnd"] = episode.IndexNumberEnd; + dataObject["EpisodeNumberEnd00"] = episode.IndexNumberEnd.Value.ToString("00", CultureInfo.InvariantCulture); + dataObject["EpisodeNumberEnd000"] = episode.IndexNumberEnd.Value.ToString("000", CultureInfo.InvariantCulture); + } + + if (episode.Series?.ProductionYear is not null) + { + dataObject["Year"] = episode.Series.ProductionYear; + } + + break; + case Audio audio: + if (!string.IsNullOrEmpty(audio.Album)) + { + dataObject["Album"] = audio.Album; + } + + if (audio.Artists.Count != 0) + { + // Should all artists be sent? + dataObject["Artist"] = audio.Artists[0]; + } + + if (audio.ProductionYear is not null) + { + dataObject["Year"] = audio.ProductionYear; + } + + break; + + case MusicAlbum album: + if (album.Artists.Count != 0) + { + // Should all artists be sent? + dataObject["Artist"] = album.Artists[0]; + } + + if (album.ProductionYear is not null) + { + dataObject["Year"] = album.ProductionYear; + } + + break; + } + + foreach (var (providerKey, providerValue) in item.ProviderIds) + { + dataObject[$"Provider_{providerKey.ToLowerInvariant()}"] = providerValue; + } + + var itemMediaStreams = item.GetMediaStreams(); + if (itemMediaStreams is not null) + { + var streamCounter = new Dictionary(); + foreach (var mediaStream in itemMediaStreams) + { + streamCounter.TryGetValue(mediaStream.Type, out var count); + streamCounter[mediaStream.Type] = count + 1; + var baseKey = $"{mediaStream.Type}_{count}"; + + switch (mediaStream.Type) + { + case MediaStreamType.Audio: { - case MediaStreamType.Audio: - { - dataObject[baseKey + "_Title"] = mediaStream.DisplayTitle; - dataObject[baseKey + "_Type"] = mediaStream.Type.ToString(); - dataObject[baseKey + "_Language"] = mediaStream.Language; - dataObject[baseKey + "_Codec"] = mediaStream.Codec; - dataObject[baseKey + "_Channels"] = mediaStream.Channels ?? 0; - dataObject[baseKey + "_Bitrate"] = mediaStream.BitRate ?? 0; - dataObject[baseKey + "_SampleRate"] = mediaStream.SampleRate ?? 0; - dataObject[baseKey + "_Default"] = mediaStream.IsDefault; - break; - } - - case MediaStreamType.Video: - { - dataObject[baseKey + "_Title"] = mediaStream.DisplayTitle; - dataObject[baseKey + "_Type"] = mediaStream.Type.ToString(); - dataObject[baseKey + "_Codec"] = mediaStream.Codec; - dataObject[baseKey + "_Profile"] = mediaStream.Profile; - dataObject[baseKey + "_Level"] = mediaStream.Level ?? 0; - dataObject[baseKey + "_Height"] = mediaStream.Height ?? 0; - dataObject[baseKey + "_Width"] = mediaStream.Width ?? 0; - dataObject[baseKey + "_AspectRatio"] = mediaStream.AspectRatio; - dataObject[baseKey + "_Interlaced"] = mediaStream.IsInterlaced; - dataObject[baseKey + "_FrameRate"] = mediaStream.RealFrameRate ?? 0; - dataObject[baseKey + "_VideoRange"] = mediaStream.VideoRange; - dataObject[baseKey + "_ColorSpace"] = mediaStream.ColorSpace; - dataObject[baseKey + "_ColorTransfer"] = mediaStream.ColorTransfer; - dataObject[baseKey + "_ColorPrimaries"] = mediaStream.ColorPrimaries; - dataObject[baseKey + "_PixelFormat"] = mediaStream.PixelFormat; - dataObject[baseKey + "_RefFrames"] = mediaStream.RefFrames ?? 0; - break; - } - - case MediaStreamType.Subtitle: - dataObject[baseKey + "_Title"] = mediaStream.DisplayTitle; - dataObject[baseKey + "_Type"] = mediaStream.Type.ToString(); - dataObject[baseKey + "_Language"] = mediaStream.Language; - dataObject[baseKey + "_Codec"] = mediaStream.Codec; - dataObject[baseKey + "_Default"] = mediaStream.IsDefault; - dataObject[baseKey + "_Forced"] = mediaStream.IsForced; - dataObject[baseKey + "_External"] = mediaStream.IsExternal; - break; + dataObject[baseKey + "_Title"] = mediaStream.DisplayTitle; + dataObject[baseKey + "_Type"] = mediaStream.Type.ToString(); + dataObject[baseKey + "_Language"] = mediaStream.Language; + dataObject[baseKey + "_Codec"] = mediaStream.Codec; + dataObject[baseKey + "_Channels"] = mediaStream.Channels ?? 0; + dataObject[baseKey + "_Bitrate"] = mediaStream.BitRate ?? 0; + dataObject[baseKey + "_SampleRate"] = mediaStream.SampleRate ?? 0; + dataObject[baseKey + "_Default"] = mediaStream.IsDefault; + break; } + + case MediaStreamType.Video: + { + dataObject[baseKey + "_Title"] = mediaStream.DisplayTitle; + dataObject[baseKey + "_Type"] = mediaStream.Type.ToString(); + dataObject[baseKey + "_Codec"] = mediaStream.Codec; + dataObject[baseKey + "_Profile"] = mediaStream.Profile; + dataObject[baseKey + "_Level"] = mediaStream.Level ?? 0; + dataObject[baseKey + "_Height"] = mediaStream.Height ?? 0; + dataObject[baseKey + "_Width"] = mediaStream.Width ?? 0; + dataObject[baseKey + "_AspectRatio"] = mediaStream.AspectRatio; + dataObject[baseKey + "_Interlaced"] = mediaStream.IsInterlaced; + dataObject[baseKey + "_FrameRate"] = mediaStream.RealFrameRate ?? 0; + dataObject[baseKey + "_VideoRange"] = mediaStream.VideoRange; + dataObject[baseKey + "_ColorSpace"] = mediaStream.ColorSpace; + dataObject[baseKey + "_ColorTransfer"] = mediaStream.ColorTransfer; + dataObject[baseKey + "_ColorPrimaries"] = mediaStream.ColorPrimaries; + dataObject[baseKey + "_PixelFormat"] = mediaStream.PixelFormat; + dataObject[baseKey + "_RefFrames"] = mediaStream.RefFrames ?? 0; + break; + } + + case MediaStreamType.Subtitle: + dataObject[baseKey + "_Title"] = mediaStream.DisplayTitle; + dataObject[baseKey + "_Type"] = mediaStream.Type.ToString(); + dataObject[baseKey + "_Language"] = mediaStream.Language; + dataObject[baseKey + "_Codec"] = mediaStream.Codec; + dataObject[baseKey + "_Default"] = mediaStream.IsDefault; + dataObject[baseKey + "_Forced"] = mediaStream.IsForced; + dataObject[baseKey + "_External"] = mediaStream.IsExternal; + break; } } - - return dataObject; } - /// - /// Add playback progress data. - /// - /// The data object. - /// The playback progress event args. - /// The modified data object. - public static Dictionary AddPlaybackProgressData(this Dictionary dataObject, PlaybackProgressEventArgs playbackProgressEventArgs) - { - dataObject[nameof(playbackProgressEventArgs.PlaybackPositionTicks)] = playbackProgressEventArgs.PlaybackPositionTicks ?? 0; - dataObject["PlaybackPosition"] = TimeSpan.FromTicks(playbackProgressEventArgs.PlaybackPositionTicks ?? 0).ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture); - dataObject[nameof(playbackProgressEventArgs.MediaSourceId)] = playbackProgressEventArgs.MediaSourceId; - dataObject[nameof(playbackProgressEventArgs.IsPaused)] = playbackProgressEventArgs.IsPaused; - dataObject[nameof(playbackProgressEventArgs.IsAutomated)] = playbackProgressEventArgs.IsAutomated; - dataObject[nameof(playbackProgressEventArgs.DeviceId)] = playbackProgressEventArgs.DeviceId; - dataObject[nameof(playbackProgressEventArgs.DeviceName)] = playbackProgressEventArgs.DeviceName; - dataObject[nameof(playbackProgressEventArgs.ClientName)] = playbackProgressEventArgs.ClientName; - - return dataObject; - } - - /// - /// Add user data. - /// - /// The data object. - /// The user to add. - /// The modified data object. - public static Dictionary AddUserData(this Dictionary dataObject, UserDto user) - { - dataObject["NotificationUsername"] = user.Name.Escape(); - dataObject["UserId"] = user.Id; - dataObject[nameof(user.LastLoginDate)] = user.LastLoginDate ?? DateTime.UtcNow; - dataObject[nameof(user.LastActivityDate)] = user.LastActivityDate ?? DateTime.MinValue; - - return dataObject; - } - - /// - /// Add user data. - /// - /// The data object. - /// The user to add. - /// The modified data object. - public static Dictionary AddUserData(this Dictionary dataObject, User user) - { - dataObject["NotificationUsername"] = user.Username.Escape(); - dataObject["UserId"] = user.Id; - dataObject[nameof(user.LastLoginDate)] = user.LastLoginDate ?? DateTime.UtcNow; - dataObject[nameof(user.LastActivityDate)] = user.LastActivityDate ?? DateTime.MinValue; - - return dataObject; - } - - /// - /// Add session info data. - /// - /// The data object. - /// The session info to add. - /// The modified data object. - public static Dictionary AddSessionInfoData(this Dictionary dataObject, SessionInfo sessionInfo) - { - dataObject[nameof(sessionInfo.Id)] = sessionInfo.Id; - dataObject[nameof(sessionInfo.UserId)] = sessionInfo.UserId; - dataObject["NotificationUsername"] = sessionInfo.UserName.Escape(); - dataObject[nameof(sessionInfo.Client)] = sessionInfo.Client.Escape(); - dataObject[nameof(sessionInfo.LastActivityDate)] = sessionInfo.LastActivityDate; - dataObject[nameof(sessionInfo.LastPlaybackCheckIn)] = sessionInfo.LastPlaybackCheckIn; - dataObject[nameof(sessionInfo.DeviceName)] = sessionInfo.DeviceName.Escape(); - dataObject[nameof(sessionInfo.DeviceId)] = sessionInfo.DeviceId; - - return dataObject; - } - - /// - /// Add plugin installation info. - /// - /// The data object. - /// The plugin installation info to add. - /// The modified data object. - public static Dictionary AddPluginInstallationInfo(this Dictionary dataObject, InstallationInfo installationInfo) - { - dataObject["PluginId"] = installationInfo.Id; - dataObject["PluginName"] = installationInfo.Name.Escape(); - dataObject["PluginVersion"] = installationInfo.Version; - dataObject["PluginChangelog"] = installationInfo.Changelog.Escape(); - dataObject["PluginChecksum"] = installationInfo.Checksum; - dataObject["PluginSourceUrl"] = installationInfo.SourceUrl; - - return dataObject; - } - - /// - /// Add exception info. - /// - /// The data object. - /// The exception to add. - /// The modified data object. - public static Dictionary AddExceptionInfo(this Dictionary dataObject, Exception exception) - { - dataObject["ExceptionMessage"] = exception.Message.Escape(); - dataObject["ExceptionMessageInner"] = exception.InnerException?.Message ?? string.Empty; - - return dataObject; - } - - /// - /// Add user item data. - /// - /// The data object. - /// The user item data. - /// The modified data object. - public static Dictionary AddUserItemData(this Dictionary dataObject, UserItemData userItemData) - { - dataObject["Likes"] = userItemData.Likes ?? false; - dataObject["Rating"] = userItemData.Rating ?? 0; - dataObject["PlaybackPositionTicks"] = userItemData.PlaybackPositionTicks; - dataObject["PlaybackPosition"] = TimeSpan.FromTicks(userItemData.PlaybackPositionTicks).ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture); - dataObject["PlayCount"] = userItemData.PlayCount; - dataObject["Favorite"] = userItemData.IsFavorite; - dataObject["Played"] = userItemData.Played; - dataObject["AudioStreamIndex"] = userItemData.AudioStreamIndex ?? -1; - dataObject["SubtitleStreamIndex"] = userItemData.SubtitleStreamIndex ?? -1; - if (userItemData.LastPlayedDate.HasValue) - { - dataObject["LastPlayedDate"] = userItemData.LastPlayedDate; - } - - return dataObject; - } - - /// - /// Escape quotes for proper json. - /// - /// Input string. - /// Escaped string. - private static string Escape(this string? input) - => input?.Replace("\"", "\\\"", StringComparison.Ordinal) ?? string.Empty; + return dataObject; } + + /// + /// Add playback progress data. + /// + /// The data object. + /// The playback progress event args. + /// The modified data object. + public static Dictionary AddPlaybackProgressData(this Dictionary dataObject, PlaybackProgressEventArgs playbackProgressEventArgs) + { + dataObject[nameof(playbackProgressEventArgs.PlaybackPositionTicks)] = playbackProgressEventArgs.PlaybackPositionTicks ?? 0; + dataObject["PlaybackPosition"] = TimeSpan.FromTicks(playbackProgressEventArgs.PlaybackPositionTicks ?? 0).ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture); + dataObject[nameof(playbackProgressEventArgs.MediaSourceId)] = playbackProgressEventArgs.MediaSourceId; + dataObject[nameof(playbackProgressEventArgs.IsPaused)] = playbackProgressEventArgs.IsPaused; + dataObject[nameof(playbackProgressEventArgs.IsAutomated)] = playbackProgressEventArgs.IsAutomated; + dataObject[nameof(playbackProgressEventArgs.DeviceId)] = playbackProgressEventArgs.DeviceId; + dataObject[nameof(playbackProgressEventArgs.DeviceName)] = playbackProgressEventArgs.DeviceName; + dataObject[nameof(playbackProgressEventArgs.ClientName)] = playbackProgressEventArgs.ClientName; + + return dataObject; + } + + /// + /// Add user data. + /// + /// The data object. + /// The user to add. + /// The modified data object. + public static Dictionary AddUserData(this Dictionary dataObject, UserDto user) + { + dataObject["NotificationUsername"] = user.Name.Escape(); + dataObject["UserId"] = user.Id; + dataObject[nameof(user.LastLoginDate)] = user.LastLoginDate ?? DateTime.UtcNow; + dataObject[nameof(user.LastActivityDate)] = user.LastActivityDate ?? DateTime.MinValue; + + return dataObject; + } + + /// + /// Add user data. + /// + /// The data object. + /// The user to add. + /// The modified data object. + public static Dictionary AddUserData(this Dictionary dataObject, User user) + { + dataObject["NotificationUsername"] = user.Username.Escape(); + dataObject["UserId"] = user.Id; + dataObject[nameof(user.LastLoginDate)] = user.LastLoginDate ?? DateTime.UtcNow; + dataObject[nameof(user.LastActivityDate)] = user.LastActivityDate ?? DateTime.MinValue; + + return dataObject; + } + + /// + /// Add session info data. + /// + /// The data object. + /// The session info to add. + /// The modified data object. + public static Dictionary AddSessionInfoData(this Dictionary dataObject, SessionInfo sessionInfo) + { + dataObject[nameof(sessionInfo.Id)] = sessionInfo.Id; + dataObject[nameof(sessionInfo.UserId)] = sessionInfo.UserId; + dataObject["NotificationUsername"] = sessionInfo.UserName.Escape(); + dataObject[nameof(sessionInfo.Client)] = sessionInfo.Client.Escape(); + dataObject[nameof(sessionInfo.LastActivityDate)] = sessionInfo.LastActivityDate; + dataObject[nameof(sessionInfo.LastPlaybackCheckIn)] = sessionInfo.LastPlaybackCheckIn; + dataObject[nameof(sessionInfo.DeviceName)] = sessionInfo.DeviceName.Escape(); + dataObject[nameof(sessionInfo.DeviceId)] = sessionInfo.DeviceId; + + return dataObject; + } + + /// + /// Add plugin installation info. + /// + /// The data object. + /// The plugin installation info to add. + /// The modified data object. + public static Dictionary AddPluginInstallationInfo(this Dictionary dataObject, InstallationInfo installationInfo) + { + dataObject["PluginId"] = installationInfo.Id; + dataObject["PluginName"] = installationInfo.Name.Escape(); + dataObject["PluginVersion"] = installationInfo.Version; + dataObject["PluginChangelog"] = installationInfo.Changelog.Escape(); + dataObject["PluginChecksum"] = installationInfo.Checksum; + dataObject["PluginSourceUrl"] = installationInfo.SourceUrl; + + return dataObject; + } + + /// + /// Add exception info. + /// + /// The data object. + /// The exception to add. + /// The modified data object. + public static Dictionary AddExceptionInfo(this Dictionary dataObject, Exception exception) + { + dataObject["ExceptionMessage"] = exception.Message.Escape(); + dataObject["ExceptionMessageInner"] = exception.InnerException?.Message ?? string.Empty; + + return dataObject; + } + + /// + /// Add user item data. + /// + /// The data object. + /// The user item data. + /// The modified data object. + public static Dictionary AddUserItemData(this Dictionary dataObject, UserItemData userItemData) + { + dataObject["Likes"] = userItemData.Likes ?? false; + dataObject["Rating"] = userItemData.Rating ?? 0; + dataObject["PlaybackPositionTicks"] = userItemData.PlaybackPositionTicks; + dataObject["PlaybackPosition"] = TimeSpan.FromTicks(userItemData.PlaybackPositionTicks).ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture); + dataObject["PlayCount"] = userItemData.PlayCount; + dataObject["Favorite"] = userItemData.IsFavorite; + dataObject["Played"] = userItemData.Played; + dataObject["AudioStreamIndex"] = userItemData.AudioStreamIndex ?? -1; + dataObject["SubtitleStreamIndex"] = userItemData.SubtitleStreamIndex ?? -1; + if (userItemData.LastPlayedDate.HasValue) + { + dataObject["LastPlayedDate"] = userItemData.LastPlayedDate; + } + + return dataObject; + } + + /// + /// Escape quotes for proper json. + /// + /// Input string. + /// Escaped string. + private static string Escape(this string? input) + => input?.Replace("\"", "\\\"", StringComparison.Ordinal) ?? string.Empty; } diff --git a/Jellyfin.Plugin.Webhook/Helpers/HandlebarsFunctionHelpers.cs b/Jellyfin.Plugin.Webhook/Helpers/HandlebarsFunctionHelpers.cs index bd41a0f..cefeea8 100644 --- a/Jellyfin.Plugin.Webhook/Helpers/HandlebarsFunctionHelpers.cs +++ b/Jellyfin.Plugin.Webhook/Helpers/HandlebarsFunctionHelpers.cs @@ -2,88 +2,87 @@ using System.Globalization; using HandlebarsDotNet; -namespace Jellyfin.Plugin.Webhook.Helpers +namespace Jellyfin.Plugin.Webhook.Helpers; + +/// +/// Handlebar helpers. +/// +public static class HandlebarsFunctionHelpers { - /// - /// Handlebar helpers. - /// - public static class HandlebarsFunctionHelpers + private static readonly HandlebarsBlockHelper StringEqualityHelper = (output, options, context, arguments) => { - private static readonly HandlebarsBlockHelper StringEqualityHelper = (output, options, context, arguments) => + if (arguments.Length != 2) { - if (arguments.Length != 2) - { - throw new HandlebarsException("{{if_equals}} helper must have exactly two arguments"); - } - - var left = GetStringValue(arguments[0]); - var right = GetStringValue(arguments[1]); - if (string.Equals(left, right, StringComparison.OrdinalIgnoreCase)) - { - options.Template(output, context); - } - else - { - options.Inverse(output, context); - } - }; - - private static readonly HandlebarsBlockHelper StringExistHelper = (output, options, context, arguments) => - { - if (arguments.Length != 1) - { - throw new HandlebarsException("{{if_exist}} helper must have exactly one argument"); - } - - var arg = GetStringValue(arguments[0]); - if (string.IsNullOrEmpty(arg)) - { - options.Inverse(output, context); - } - else - { - options.Template(output, context); - } - }; - - /// - /// Register handlebars helpers. - /// - public static void RegisterHelpers() - { - Handlebars.RegisterHelper("if_equals", StringEqualityHelper); - Handlebars.RegisterHelper("if_exist", StringExistHelper); - Handlebars.RegisterHelper("link_to", (writer, context, parameters) => - { - writer.WriteSafeString($"{context["text"]}"); - }); + throw new HandlebarsException("{{if_equals}} helper must have exactly two arguments"); } - /// - /// Base 64 decode. - /// - /// - /// The template is stored as base64 in config. - /// - /// The encoded data. - /// The decoded string. - public static string Base64Decode(string? base64EncodedData) + var left = GetStringValue(arguments[0]); + var right = GetStringValue(arguments[1]); + if (string.Equals(left, right, StringComparison.OrdinalIgnoreCase)) { - if (string.IsNullOrEmpty(base64EncodedData)) - { - return string.Empty; - } + options.Template(output, context); + } + else + { + options.Inverse(output, context); + } + }; - var base64EncodedBytes = Convert.FromBase64String(base64EncodedData); - return System.Text.Encoding.UTF8.GetString(base64EncodedBytes); + private static readonly HandlebarsBlockHelper StringExistHelper = (output, options, context, arguments) => + { + if (arguments.Length != 1) + { + throw new HandlebarsException("{{if_exist}} helper must have exactly one argument"); } - private static string? GetStringValue(object? input) + var arg = GetStringValue(arguments[0]); + if (string.IsNullOrEmpty(arg)) { - // UndefinedBindingResult means the parameter was a part of the provided dataset. - return input is UndefinedBindingResult or null - ? null - : Convert.ToString(input, CultureInfo.InvariantCulture); + options.Inverse(output, context); } + else + { + options.Template(output, context); + } + }; + + /// + /// Register handlebars helpers. + /// + public static void RegisterHelpers() + { + Handlebars.RegisterHelper("if_equals", StringEqualityHelper); + Handlebars.RegisterHelper("if_exist", StringExistHelper); + Handlebars.RegisterHelper("link_to", (writer, context, parameters) => + { + writer.WriteSafeString($"{context["text"]}"); + }); + } + + /// + /// Base 64 decode. + /// + /// + /// The template is stored as base64 in config. + /// + /// The encoded data. + /// The decoded string. + public static string Base64Decode(string? base64EncodedData) + { + if (string.IsNullOrEmpty(base64EncodedData)) + { + return string.Empty; + } + + var base64EncodedBytes = Convert.FromBase64String(base64EncodedData); + return System.Text.Encoding.UTF8.GetString(base64EncodedBytes); + } + + private static string? GetStringValue(object? input) + { + // UndefinedBindingResult means the parameter was a part of the provided dataset. + return input is UndefinedBindingResult or null + ? null + : Convert.ToString(input, CultureInfo.InvariantCulture); } } diff --git a/Jellyfin.Plugin.Webhook/IWebhookSender.cs b/Jellyfin.Plugin.Webhook/IWebhookSender.cs index a667fc0..9d4e055 100644 --- a/Jellyfin.Plugin.Webhook/IWebhookSender.cs +++ b/Jellyfin.Plugin.Webhook/IWebhookSender.cs @@ -3,20 +3,19 @@ using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Plugin.Webhook.Destinations; -namespace Jellyfin.Plugin.Webhook +namespace Jellyfin.Plugin.Webhook; + +/// +/// Webhook sender interface. +/// +public interface IWebhookSender { /// - /// Webhook sender interface. + /// Send notification with item type. /// - public interface IWebhookSender - { - /// - /// Send notification with item type. - /// - /// The notification type. - /// The item data. - /// The item type. Default null. - /// A representing the asynchronous operation. - Task SendNotification(NotificationType notificationType, Dictionary itemData, Type? itemType = null); - } + /// The notification type. + /// The item data. + /// The item type. Default null. + /// A representing the asynchronous operation. + Task SendNotification(NotificationType notificationType, Dictionary itemData, Type? itemType = null); } diff --git a/Jellyfin.Plugin.Webhook/Jellyfin.Plugin.Webhook.csproj b/Jellyfin.Plugin.Webhook/Jellyfin.Plugin.Webhook.csproj index b7a2b91..9f99631 100644 --- a/Jellyfin.Plugin.Webhook/Jellyfin.Plugin.Webhook.csproj +++ b/Jellyfin.Plugin.Webhook/Jellyfin.Plugin.Webhook.csproj @@ -15,12 +15,12 @@ - + - + diff --git a/Jellyfin.Plugin.Webhook/Models/QueuedItemContainer.cs b/Jellyfin.Plugin.Webhook/Models/QueuedItemContainer.cs index 0752be3..e3f9174 100644 --- a/Jellyfin.Plugin.Webhook/Models/QueuedItemContainer.cs +++ b/Jellyfin.Plugin.Webhook/Models/QueuedItemContainer.cs @@ -1,30 +1,29 @@ using System; -namespace Jellyfin.Plugin.Webhook.Models +namespace Jellyfin.Plugin.Webhook.Models; + +/// +/// Queued item container. +/// +public class QueuedItemContainer { /// - /// Queued item container. + /// Initializes a new instance of the class. /// - public class QueuedItemContainer + /// The item id. + public QueuedItemContainer(Guid id) { - /// - /// Initializes a new instance of the class. - /// - /// The item id. - public QueuedItemContainer(Guid id) - { - ItemId = id; - RetryCount = 0; - } - - /// - /// Gets or sets the current retry count. - /// - public int RetryCount { get; set; } - - /// - /// Gets or sets the current item id. - /// - public Guid ItemId { get; set; } + ItemId = id; + RetryCount = 0; } -} \ No newline at end of file + + /// + /// Gets or sets the current retry count. + /// + public int RetryCount { get; set; } + + /// + /// Gets or sets the current item id. + /// + public Guid ItemId { get; set; } +} diff --git a/Jellyfin.Plugin.Webhook/Notifiers/AuthenticationFailureNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/AuthenticationFailureNotifier.cs index fcde01e..90563cd 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/AuthenticationFailureNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/AuthenticationFailureNotifier.cs @@ -6,48 +6,47 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Session; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Authentication failure notifier. +/// +public class AuthenticationFailureNotifier : IEventConsumer> { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Authentication failure notifier. + /// Initializes a new instance of the class. /// - public class AuthenticationFailureNotifier : IEventConsumer> + /// Instance of the interface. + /// Instance of the interface. + public AuthenticationFailureNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public AuthenticationFailureNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) + /// + public async Task OnEvent(GenericEventArgs eventArgs) + { + if (eventArgs.Argument is null) { - _applicationHost = applicationHost; - _webhookSender = webhookSender; + return; } - /// - public async Task OnEvent(GenericEventArgs eventArgs) - { - if (eventArgs.Argument is null) - { - return; - } + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.AuthenticationFailure); + dataObject[nameof(eventArgs.Argument.App)] = eventArgs.Argument.App; + dataObject[nameof(eventArgs.Argument.Username)] = eventArgs.Argument.Username; + dataObject[nameof(eventArgs.Argument.UserId)] = eventArgs.Argument.UserId; + dataObject[nameof(eventArgs.Argument.AppVersion)] = eventArgs.Argument.AppVersion; + dataObject[nameof(eventArgs.Argument.DeviceId)] = eventArgs.Argument.DeviceId; + dataObject[nameof(eventArgs.Argument.DeviceName)] = eventArgs.Argument.DeviceName; - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.AuthenticationFailure); - dataObject[nameof(eventArgs.Argument.App)] = eventArgs.Argument.App; - dataObject[nameof(eventArgs.Argument.Username)] = eventArgs.Argument.Username; - dataObject[nameof(eventArgs.Argument.UserId)] = eventArgs.Argument.UserId; - dataObject[nameof(eventArgs.Argument.AppVersion)] = eventArgs.Argument.AppVersion; - dataObject[nameof(eventArgs.Argument.DeviceId)] = eventArgs.Argument.DeviceId; - dataObject[nameof(eventArgs.Argument.DeviceName)] = eventArgs.Argument.DeviceName; - - await _webhookSender.SendNotification(NotificationType.AuthenticationFailure, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.AuthenticationFailure, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/AuthenticationSuccessNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/AuthenticationSuccessNotifier.cs index 8e11d41..b79a92e 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/AuthenticationSuccessNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/AuthenticationSuccessNotifier.cs @@ -6,43 +6,42 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Events; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Authentication success notifier. +/// +public class AuthenticationSuccessNotifier : IEventConsumer> { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Authentication success notifier. + /// Initializes a new instance of the class. /// - public class AuthenticationSuccessNotifier : IEventConsumer> + /// Instance of the interface. + /// Instance of the interface. + public AuthenticationSuccessNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public AuthenticationSuccessNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) + /// + public async Task OnEvent(GenericEventArgs eventArgs) + { + if (eventArgs.Argument is null) { - _applicationHost = applicationHost; - _webhookSender = webhookSender; + return; } - /// - public async Task OnEvent(GenericEventArgs eventArgs) - { - if (eventArgs.Argument is null) - { - return; - } + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.AuthenticationSuccess) + .AddUserData(eventArgs.Argument.User); - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.AuthenticationSuccess) - .AddUserData(eventArgs.Argument.User); - - await _webhookSender.SendNotification(NotificationType.AuthenticationSuccess, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.AuthenticationSuccess, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/GenericNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/GenericNotifier.cs index 574710d..55034a7 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/GenericNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/GenericNotifier.cs @@ -6,48 +6,47 @@ using Jellyfin.Plugin.Webhook.Helpers; using MediaBrowser.Controller; using MediaBrowser.Controller.Notifications; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Generic notifier. +/// +public class GenericNotifier : INotificationService { + private readonly IWebhookSender _webhookSender; + private readonly IServerApplicationHost _applicationHost; + /// - /// Generic notifier. + /// Initializes a new instance of the class. /// - public class GenericNotifier : INotificationService + /// Instance of the interface. + /// Instance of the interface. + public GenericNotifier(IWebhookSender webhookSender, IServerApplicationHost applicationHost) { - private readonly IWebhookSender _webhookSender; - private readonly IServerApplicationHost _applicationHost; - - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public GenericNotifier(IWebhookSender webhookSender, IServerApplicationHost applicationHost) - { - _webhookSender = webhookSender; - _applicationHost = applicationHost; - } - - /// - public string Name => "Webhook: Generic Notifier"; - - /// - public async Task SendNotification(UserNotification request, CancellationToken cancellationToken) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.Generic); - dataObject[nameof(request.Name)] = request.Name; - dataObject[nameof(request.Description)] = request.Description; - dataObject[nameof(request.Date)] = request.Date; - dataObject[nameof(request.Level)] = request.Level; - dataObject[nameof(request.Url)] = request.Url; - dataObject[nameof(request.User.Username)] = request.User.Username; - dataObject["UserId"] = request.User.Id; - - await _webhookSender.SendNotification(NotificationType.Generic, dataObject) - .ConfigureAwait(false); - } - - /// - public bool IsEnabledForUser(User user) => true; + _webhookSender = webhookSender; + _applicationHost = applicationHost; } + + /// + public string Name => "Webhook: Generic Notifier"; + + /// + public async Task SendNotification(UserNotification request, CancellationToken cancellationToken) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.Generic); + dataObject[nameof(request.Name)] = request.Name; + dataObject[nameof(request.Description)] = request.Description; + dataObject[nameof(request.Date)] = request.Date; + dataObject[nameof(request.Level)] = request.Level; + dataObject[nameof(request.Url)] = request.Url; + dataObject[nameof(request.User.Username)] = request.User.Username; + dataObject["UserId"] = request.User.Id; + + await _webhookSender.SendNotification(NotificationType.Generic, dataObject) + .ConfigureAwait(false); + } + + /// + public bool IsEnabledForUser(User user) => true; } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/IItemAddedManager.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/IItemAddedManager.cs index aa872d1..ffef2a2 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/IItemAddedManager.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/IItemAddedManager.cs @@ -1,23 +1,22 @@ using System.Threading.Tasks; using MediaBrowser.Controller.Entities; -namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier +namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier; + +/// +/// Item added manager interface. +/// +public interface IItemAddedManager { /// - /// Item added manager interface. + /// Process the current queue. /// - public interface IItemAddedManager - { - /// - /// Process the current queue. - /// - /// A representing the asynchronous operation. - public Task ProcessItemsAsync(); + /// A representing the asynchronous operation. + public Task ProcessItemsAsync(); - /// - /// Add item to process queue. - /// - /// The added item. - public void AddItem(BaseItem item); - } -} \ No newline at end of file + /// + /// Add item to process queue. + /// + /// The added item. + public void AddItem(BaseItem item); +} diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedManager.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedManager.cs index fbd52fc..2196812 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedManager.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedManager.cs @@ -9,86 +9,85 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier +namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier; + +/// +public class ItemAddedManager : IItemAddedManager { - /// - public class ItemAddedManager : IItemAddedManager + private const int MaxRetries = 10; + private readonly ILogger _logger; + private readonly ILibraryManager _libraryManager; + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + private readonly ConcurrentDictionary _itemProcessQueue; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public ItemAddedManager( + ILogger logger, + ILibraryManager libraryManager, + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private const int MaxRetries = 10; - private readonly ILogger _logger; - private readonly ILibraryManager _libraryManager; - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; - private readonly ConcurrentDictionary _itemProcessQueue; + _logger = logger; + _libraryManager = libraryManager; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + _itemProcessQueue = new ConcurrentDictionary(); + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - /// Instance of the interface. - /// Instance of the interface. - public ItemAddedManager( - ILogger logger, - ILibraryManager libraryManager, - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) + /// + public async Task ProcessItemsAsync() + { + _logger.LogDebug("ProcessItemsAsync"); + // Attempt to process all items in queue. + var currentItems = _itemProcessQueue.ToArray(); + foreach (var (key, container) in currentItems) { - _logger = logger; - _libraryManager = libraryManager; - _applicationHost = applicationHost; - _webhookSender = webhookSender; - _itemProcessQueue = new ConcurrentDictionary(); - } - - /// - public async Task ProcessItemsAsync() - { - _logger.LogDebug("ProcessItemsAsync"); - // Attempt to process all items in queue. - var currentItems = _itemProcessQueue.ToArray(); - foreach (var (key, container) in currentItems) + var item = _libraryManager.GetItemById(key); + if (item is null) { - var item = _libraryManager.GetItemById(key); - if (item is null) - { - // Remove item from queue. - _itemProcessQueue.TryRemove(key, out _); - return; - } - - _logger.LogDebug("Item {ItemName}", item.Name); - - // Metadata not refreshed yet and under retry limit. - if (item.ProviderIds.Keys.Count == 0 && container.RetryCount < MaxRetries) - { - _logger.LogDebug("Requeue {ItemName}, no provider ids", item.Name); - container.RetryCount++; - _itemProcessQueue.AddOrUpdate(key, container, (_, _) => container); - continue; - } - - _logger.LogDebug("Notifying for {ItemName}", item.Name); - - // Send notification to each configured destination. - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.ItemAdded) - .AddBaseItemData(item); - - var itemType = item.GetType(); - await _webhookSender.SendNotification(NotificationType.ItemAdded, dataObject, itemType) - .ConfigureAwait(false); - // Remove item from queue. _itemProcessQueue.TryRemove(key, out _); + return; } - } - /// - public void AddItem(BaseItem item) - { - _itemProcessQueue.TryAdd(item.Id, new QueuedItemContainer(item.Id)); - _logger.LogDebug("Queued {ItemName} for notification", item.Name); + _logger.LogDebug("Item {ItemName}", item.Name); + + // Metadata not refreshed yet and under retry limit. + if (item.ProviderIds.Keys.Count == 0 && container.RetryCount < MaxRetries) + { + _logger.LogDebug("Requeue {ItemName}, no provider ids", item.Name); + container.RetryCount++; + _itemProcessQueue.AddOrUpdate(key, container, (_, _) => container); + continue; + } + + _logger.LogDebug("Notifying for {ItemName}", item.Name); + + // Send notification to each configured destination. + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.ItemAdded) + .AddBaseItemData(item); + + var itemType = item.GetType(); + await _webhookSender.SendNotification(NotificationType.ItemAdded, dataObject, itemType) + .ConfigureAwait(false); + + // Remove item from queue. + _itemProcessQueue.TryRemove(key, out _); } } + + /// + public void AddItem(BaseItem item) + { + _itemProcessQueue.TryAdd(item.Id, new QueuedItemContainer(item.Id)); + _logger.LogDebug("Queued {ItemName} for notification", item.Name); + } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedNotifierEntryPoint.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedNotifierEntryPoint.cs index 0ac0216..2dd6153 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedNotifierEntryPoint.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedNotifierEntryPoint.cs @@ -4,65 +4,64 @@ using Jellyfin.Plugin.Webhook.Helpers; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; -namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier +namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier; + +/// +/// Notifier when a library item is added. +/// +public class ItemAddedNotifierEntryPoint : IServerEntryPoint { + private readonly IItemAddedManager _itemAddedManager; + private readonly ILibraryManager _libraryManager; + /// - /// Notifier when a library item is added. + /// Initializes a new instance of the class. /// - public class ItemAddedNotifierEntryPoint : IServerEntryPoint + /// Instance of the interface. + /// Instance of the interface. + public ItemAddedNotifierEntryPoint( + IItemAddedManager itemAddedManager, + ILibraryManager libraryManager) { - private readonly IItemAddedManager _itemAddedManager; - private readonly ILibraryManager _libraryManager; + _itemAddedManager = itemAddedManager; + _libraryManager = libraryManager; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public ItemAddedNotifierEntryPoint( - IItemAddedManager itemAddedManager, - ILibraryManager libraryManager) + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + public Task RunAsync() + { + _libraryManager.ItemAdded += ItemAddedHandler; + HandlebarsFunctionHelpers.RegisterHelpers(); + return Task.CompletedTask; + } + + /// + /// Dispose. + /// + /// Dispose all assets. + protected virtual void Dispose(bool disposing) + { + if (disposing) { - _itemAddedManager = itemAddedManager; - _libraryManager = libraryManager; - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - public Task RunAsync() - { - _libraryManager.ItemAdded += ItemAddedHandler; - HandlebarsFunctionHelpers.RegisterHelpers(); - return Task.CompletedTask; - } - - /// - /// Dispose. - /// - /// Dispose all assets. - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _libraryManager.ItemAdded -= ItemAddedHandler; - } - } - - private void ItemAddedHandler(object? sender, ItemChangeEventArgs itemChangeEventArgs) - { - // Never notify on virtual items. - if (itemChangeEventArgs.Item.IsVirtualItem) - { - return; - } - - _itemAddedManager.AddItem(itemChangeEventArgs.Item); + _libraryManager.ItemAdded -= ItemAddedHandler; } } -} \ No newline at end of file + + private void ItemAddedHandler(object? sender, ItemChangeEventArgs itemChangeEventArgs) + { + // Never notify on virtual items. + if (itemChangeEventArgs.Item.IsVirtualItem) + { + return; + } + + _itemAddedManager.AddItem(itemChangeEventArgs.Item); + } +} diff --git a/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedScheduledTask.cs b/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedScheduledTask.cs index 8374680..6d8d2d7 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedScheduledTask.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/ItemAddedNotifier/ItemAddedScheduledTask.cs @@ -5,68 +5,67 @@ using System.Threading.Tasks; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Tasks; -namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier +namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier; + +/// +/// Scheduled task that processes item added events. +/// +public class ItemAddedScheduledTask : IScheduledTask, IConfigurableScheduledTask { + private const int RecheckIntervalSec = 30; + private readonly IItemAddedManager _itemAddedManager; + private readonly ILocalizationManager _localizationManager; + /// - /// Scheduled task that processes item added events. + /// Initializes a new instance of the class. /// - public class ItemAddedScheduledTask : IScheduledTask, IConfigurableScheduledTask + /// Instance of the interface. + /// Instance of the interface. + public ItemAddedScheduledTask( + IItemAddedManager itemAddedManager, + ILocalizationManager localizationManager) { - private const int RecheckIntervalSec = 30; - private readonly IItemAddedManager _itemAddedManager; - private readonly ILocalizationManager _localizationManager; + _itemAddedManager = itemAddedManager; + _localizationManager = localizationManager; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public ItemAddedScheduledTask( - IItemAddedManager itemAddedManager, - ILocalizationManager localizationManager) + /// + public string Name => "Webhook Item Added Notifier"; + + /// + public string Key => "WebhookItemAdded"; + + /// + public string Description => "Processes item added 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 _itemAddedManager.ProcessItemsAsync(); + } + + /// + public IEnumerable GetDefaultTriggers() + { + return new[] { - _itemAddedManager = itemAddedManager; - _localizationManager = localizationManager; - } - - /// - public string Name => "Webhook Item Added Notifier"; - - /// - public string Key => "WebhookItemAdded"; - - /// - public string Description => "Processes item added 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 _itemAddedManager.ProcessItemsAsync(); - } - - /// - public IEnumerable GetDefaultTriggers() - { - return new[] + new TaskTriggerInfo { - new TaskTriggerInfo - { - Type = TaskTriggerInfo.TriggerInterval, - IntervalTicks = TimeSpan.FromSeconds(RecheckIntervalSec).Ticks - } - }; - } + Type = TaskTriggerInfo.TriggerInterval, + IntervalTicks = TimeSpan.FromSeconds(RecheckIntervalSec).Ticks + } + }; } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PendingRestartNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PendingRestartNotifier.cs index 0c2b881..7fcb074 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PendingRestartNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PendingRestartNotifier.cs @@ -5,37 +5,36 @@ using Jellyfin.Plugin.Webhook.Helpers; using MediaBrowser.Controller; using MediaBrowser.Controller.Events; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Pending restart notifier. +/// +public class PendingRestartNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Pending restart notifier. + /// Initializes a new instance of the class. /// - public class PendingRestartNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public PendingRestartNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PendingRestartNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(PendingRestartEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PendingRestart); - /// - public async Task OnEvent(PendingRestartEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PendingRestart); - - await _webhookSender.SendNotification(NotificationType.PendingRestart, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PendingRestart, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PlaybackProgressNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PlaybackProgressNotifier.cs index 6557d11..b325790 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PlaybackProgressNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PlaybackProgressNotifier.cs @@ -6,65 +6,64 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Library; -namespace Jellyfin.Plugin.Webhook.Notifiers -{ - /// - /// Playback progress notifier. - /// - public class PlaybackProgressNotifier : IEventConsumer - { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; +namespace Jellyfin.Plugin.Webhook.Notifiers; - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PlaybackProgressNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) +/// +/// Playback progress notifier. +/// +public class PlaybackProgressNotifier : IEventConsumer +{ + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + public PlaybackProgressNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) + { + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } + + /// + public async Task OnEvent(PlaybackProgressEventArgs eventArgs) + { + if (eventArgs.Item is null) { - _applicationHost = applicationHost; - _webhookSender = webhookSender; + return; } - /// - public async Task OnEvent(PlaybackProgressEventArgs eventArgs) + if (eventArgs.Item.IsThemeMedia) { - if (eventArgs.Item is null) + // Don't report theme song or local trailer playback. + return; + } + + if (eventArgs.Users.Count == 0) + { + // No users in playback session. + return; + } + + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PlaybackProgress) + .AddBaseItemData(eventArgs.Item) + .AddPlaybackProgressData(eventArgs); + + foreach (var user in eventArgs.Users) + { + var userDataObject = new Dictionary(dataObject) { - return; - } + ["NotificationUsername"] = user.Username, + ["UserId"] = user.Id + }; - if (eventArgs.Item.IsThemeMedia) - { - // Don't report theme song or local trailer playback. - return; - } - - if (eventArgs.Users.Count == 0) - { - // No users in playback session. - return; - } - - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PlaybackProgress) - .AddBaseItemData(eventArgs.Item) - .AddPlaybackProgressData(eventArgs); - - foreach (var user in eventArgs.Users) - { - var userDataObject = new Dictionary(dataObject) - { - ["NotificationUsername"] = user.Username, - ["UserId"] = user.Id - }; - - await _webhookSender.SendNotification(NotificationType.PlaybackProgress, userDataObject, eventArgs.Item.GetType()) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PlaybackProgress, userDataObject, eventArgs.Item.GetType()) + .ConfigureAwait(false); } } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PlaybackStartNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PlaybackStartNotifier.cs index 6cd512d..8072da6 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PlaybackStartNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PlaybackStartNotifier.cs @@ -6,65 +6,64 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Library; -namespace Jellyfin.Plugin.Webhook.Notifiers -{ - /// - /// Playback start notifier. - /// - public class PlaybackStartNotifier : IEventConsumer - { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; +namespace Jellyfin.Plugin.Webhook.Notifiers; - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PlaybackStartNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) +/// +/// Playback start notifier. +/// +public class PlaybackStartNotifier : IEventConsumer +{ + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + public PlaybackStartNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) + { + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } + + /// + public async Task OnEvent(PlaybackStartEventArgs eventArgs) + { + if (eventArgs.Item is null) { - _applicationHost = applicationHost; - _webhookSender = webhookSender; + return; } - /// - public async Task OnEvent(PlaybackStartEventArgs eventArgs) + if (eventArgs.Item.IsThemeMedia) { - if (eventArgs.Item is null) + // Don't report theme song or local trailer playback. + return; + } + + if (eventArgs.Users.Count == 0) + { + // No users in playback session. + return; + } + + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PlaybackStart) + .AddBaseItemData(eventArgs.Item) + .AddPlaybackProgressData(eventArgs); + + foreach (var user in eventArgs.Users) + { + var userDataObject = new Dictionary(dataObject) { - return; - } + ["NotificationUsername"] = user.Username, + ["UserId"] = user.Id + }; - if (eventArgs.Item.IsThemeMedia) - { - // Don't report theme song or local trailer playback. - return; - } - - if (eventArgs.Users.Count == 0) - { - // No users in playback session. - return; - } - - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PlaybackStart) - .AddBaseItemData(eventArgs.Item) - .AddPlaybackProgressData(eventArgs); - - foreach (var user in eventArgs.Users) - { - var userDataObject = new Dictionary(dataObject) - { - ["NotificationUsername"] = user.Username, - ["UserId"] = user.Id - }; - - await _webhookSender.SendNotification(NotificationType.PlaybackStart, userDataObject, eventArgs.Item.GetType()) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PlaybackStart, userDataObject, eventArgs.Item.GetType()) + .ConfigureAwait(false); } } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PlaybackStopNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PlaybackStopNotifier.cs index 5547bf1..6c7dbf4 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PlaybackStopNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PlaybackStopNotifier.cs @@ -6,66 +6,65 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Library; -namespace Jellyfin.Plugin.Webhook.Notifiers -{ - /// - /// Playback stop notifier. - /// - public class PlaybackStopNotifier : IEventConsumer - { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; +namespace Jellyfin.Plugin.Webhook.Notifiers; - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PlaybackStopNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) +/// +/// Playback stop notifier. +/// +public class PlaybackStopNotifier : IEventConsumer +{ + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + public PlaybackStopNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) + { + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } + + /// + public async Task OnEvent(PlaybackStopEventArgs eventArgs) + { + if (eventArgs.Item is null) { - _applicationHost = applicationHost; - _webhookSender = webhookSender; + return; } - /// - public async Task OnEvent(PlaybackStopEventArgs eventArgs) + if (eventArgs.Item.IsThemeMedia) { - if (eventArgs.Item is null) + // Don't report theme song or local trailer playback. + return; + } + + if (eventArgs.Users.Count == 0) + { + // No users in playback session. + return; + } + + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PlaybackStop) + .AddBaseItemData(eventArgs.Item) + .AddPlaybackProgressData(eventArgs); + dataObject[nameof(eventArgs.PlayedToCompletion)] = eventArgs.PlayedToCompletion; + + foreach (var user in eventArgs.Users) + { + var userDataObject = new Dictionary(dataObject) { - return; - } + ["NotificationUsername"] = user.Username, + ["UserId"] = user.Id + }; - if (eventArgs.Item.IsThemeMedia) - { - // Don't report theme song or local trailer playback. - return; - } - - if (eventArgs.Users.Count == 0) - { - // No users in playback session. - return; - } - - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PlaybackStop) - .AddBaseItemData(eventArgs.Item) - .AddPlaybackProgressData(eventArgs); - dataObject[nameof(eventArgs.PlayedToCompletion)] = eventArgs.PlayedToCompletion; - - foreach (var user in eventArgs.Users) - { - var userDataObject = new Dictionary(dataObject) - { - ["NotificationUsername"] = user.Username, - ["UserId"] = user.Id - }; - - await _webhookSender.SendNotification(NotificationType.PlaybackStop, userDataObject, eventArgs.Item.GetType()) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PlaybackStop, userDataObject, eventArgs.Item.GetType()) + .ConfigureAwait(false); } } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallationCancelledNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallationCancelledNotifier.cs index 41206f9..62f6718 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallationCancelledNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallationCancelledNotifier.cs @@ -5,38 +5,37 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Plugin installation cancelled. +/// +public class PluginInstallationCancelledNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Plugin installation cancelled. + /// Initializes a new instance of the class. /// - public class PluginInstallationCancelledNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public PluginInstallationCancelledNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PluginInstallationCancelledNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(PluginInstallationCancelledEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PluginInstallationCancelled) + .AddPluginInstallationInfo(eventArgs.Argument); - /// - public async Task OnEvent(PluginInstallationCancelledEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PluginInstallationCancelled) - .AddPluginInstallationInfo(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.PluginInstallationCancelled, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PluginInstallationCancelled, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallationFailedNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallationFailedNotifier.cs index ae85af4..8d0c054 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallationFailedNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallationFailedNotifier.cs @@ -5,39 +5,38 @@ using MediaBrowser.Common.Updates; using MediaBrowser.Controller; using MediaBrowser.Controller.Events; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Plugin installation failed notifier. +/// +public class PluginInstallationFailedNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Plugin installation failed notifier. + /// Initializes a new instance of the class. /// - public class PluginInstallationFailedNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public PluginInstallationFailedNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PluginInstallationFailedNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(InstallationFailedEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PluginInstallationFailed) + .AddPluginInstallationInfo(eventArgs.InstallationInfo) + .AddExceptionInfo(eventArgs.Exception); - /// - public async Task OnEvent(InstallationFailedEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PluginInstallationFailed) - .AddPluginInstallationInfo(eventArgs.InstallationInfo) - .AddExceptionInfo(eventArgs.Exception); - - await _webhookSender.SendNotification(NotificationType.PluginInstallationFailed, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PluginInstallationFailed, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PluginInstalledNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PluginInstalledNotifier.cs index 465e893..4bb8904 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PluginInstalledNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PluginInstalledNotifier.cs @@ -5,38 +5,37 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Plugin installed notifier. +/// +public class PluginInstalledNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Plugin installed notifier. + /// Initializes a new instance of the class. /// - public class PluginInstalledNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public PluginInstalledNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PluginInstalledNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(PluginInstalledEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PluginInstalled) + .AddPluginInstallationInfo(eventArgs.Argument); - /// - public async Task OnEvent(PluginInstalledEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PluginInstalled) - .AddPluginInstallationInfo(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.PluginInstalled, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PluginInstalled, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallingNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallingNotifier.cs index e36c30c..2b7aae3 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallingNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PluginInstallingNotifier.cs @@ -5,38 +5,37 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Plugin installing notifier. +/// +public class PluginInstallingNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Plugin installing notifier. + /// Initializes a new instance of the class. /// - public class PluginInstallingNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public PluginInstallingNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PluginInstallingNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(PluginInstallingEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PluginInstalling) + .AddPluginInstallationInfo(eventArgs.Argument); - /// - public async Task OnEvent(PluginInstallingEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PluginInstalling) - .AddPluginInstallationInfo(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.PluginInstalling, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PluginInstalling, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PluginUninstalledNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PluginUninstalledNotifier.cs index ab55ac1..10ff6fc 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PluginUninstalledNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PluginUninstalledNotifier.cs @@ -5,42 +5,41 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Plugin uninstalled notifier. +/// +public class PluginUninstalledNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Plugin uninstalled notifier. + /// Initializes a new instance of the class. /// - public class PluginUninstalledNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public PluginUninstalledNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PluginUninstalledNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(PluginUninstalledEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PluginUninstalled); + dataObject["PluginId"] = eventArgs.Argument.Id; + dataObject["PluginName"] = eventArgs.Argument.Name; + dataObject["PluginDescription"] = eventArgs.Argument.Description; + dataObject["PluginVersion"] = eventArgs.Argument.Version; + dataObject["PluginStatus"] = eventArgs.Argument.Status; - /// - public async Task OnEvent(PluginUninstalledEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PluginUninstalled); - dataObject["PluginId"] = eventArgs.Argument.Id; - dataObject["PluginName"] = eventArgs.Argument.Name; - dataObject["PluginDescription"] = eventArgs.Argument.Description; - dataObject["PluginVersion"] = eventArgs.Argument.Version; - dataObject["PluginStatus"] = eventArgs.Argument.Status; - - await _webhookSender.SendNotification(NotificationType.PluginUninstalled, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PluginUninstalled, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/PluginUpdatedNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/PluginUpdatedNotifier.cs index 5904d4c..6ad792d 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/PluginUpdatedNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/PluginUpdatedNotifier.cs @@ -5,38 +5,37 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Plugin updated notifier. +/// +public class PluginUpdatedNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Plugin updated notifier. + /// Initializes a new instance of the class. /// - public class PluginUpdatedNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public PluginUpdatedNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public PluginUpdatedNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(PluginUpdatedEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.PluginUpdated) + .AddPluginInstallationInfo(eventArgs.Argument); - /// - public async Task OnEvent(PluginUpdatedEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.PluginUpdated) - .AddPluginInstallationInfo(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.PluginUpdated, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.PluginUpdated, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/SessionStartNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/SessionStartNotifier.cs index e853ad5..4a025e2 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/SessionStartNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/SessionStartNotifier.cs @@ -5,44 +5,43 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Session; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Session start notifier. +/// +public class SessionStartNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Session start notifier. + /// Initializes a new instance of the class. /// - public class SessionStartNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public SessionStartNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public SessionStartNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) + /// + public async Task OnEvent(SessionStartedEventArgs eventArgs) + { + if (eventArgs.Argument is null) { - _applicationHost = applicationHost; - _webhookSender = webhookSender; + return; } - /// - public async Task OnEvent(SessionStartedEventArgs eventArgs) - { - if (eventArgs.Argument is null) - { - return; - } + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.SessionStart) + .AddSessionInfoData(eventArgs.Argument) + .AddBaseItemData(eventArgs.Argument.FullNowPlayingItem); - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.SessionStart) - .AddSessionInfoData(eventArgs.Argument) - .AddBaseItemData(eventArgs.Argument.FullNowPlayingItem); - - await _webhookSender.SendNotification(NotificationType.SessionStart, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.SessionStart, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/SubtitleDownloadFailureNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/SubtitleDownloadFailureNotifier.cs index 01b3e2a..c8a8a21 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/SubtitleDownloadFailureNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/SubtitleDownloadFailureNotifier.cs @@ -5,42 +5,41 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Subtitles; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Subtitle download failure notifier. +/// +public class SubtitleDownloadFailureNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Subtitle download failure notifier. + /// Initializes a new instance of the class. /// - public class SubtitleDownloadFailureNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public SubtitleDownloadFailureNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public SubtitleDownloadFailureNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) + /// + public async Task OnEvent(SubtitleDownloadFailureEventArgs eventArgs) + { + if (eventArgs.Item is null) { - _applicationHost = applicationHost; - _webhookSender = webhookSender; + return; } - /// - public async Task OnEvent(SubtitleDownloadFailureEventArgs eventArgs) - { - if (eventArgs.Item is null) - { - return; - } - - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.SubtitleDownloadFailure) - .AddBaseItemData(eventArgs.Item); - await _webhookSender.SendNotification(NotificationType.SubtitleDownloadFailure, dataObject, eventArgs.Item.GetType()) - .ConfigureAwait(false); - } + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.SubtitleDownloadFailure) + .AddBaseItemData(eventArgs.Item); + await _webhookSender.SendNotification(NotificationType.SubtitleDownloadFailure, dataObject, eventArgs.Item.GetType()) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/TaskCompletedNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/TaskCompletedNotifier.cs index 34e8c8b..65a5e9d 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/TaskCompletedNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/TaskCompletedNotifier.cs @@ -5,50 +5,49 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Tasks; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// Task completed notifier. +/// +public class TaskCompletedNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// Task completed notifier. + /// Initializes a new instance of the class. /// - public class TaskCompletedNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public TaskCompletedNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public TaskCompletedNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(TaskCompletionEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.TaskCompleted); + dataObject["TaskId"] = eventArgs.Task.Id; + dataObject["TaskName"] = eventArgs.Task.Name; + dataObject["TaskDescription"] = eventArgs.Task.Description; + dataObject["TaskCategory"] = eventArgs.Task.Category; + dataObject["TaskState"] = eventArgs.Task.State.ToString(); + dataObject["ResultId"] = eventArgs.Result.Id; + dataObject["ResultKey"] = eventArgs.Result.Key; + dataObject["ResultName"] = eventArgs.Result.Name; + dataObject["ResultStatus"] = eventArgs.Result.Status.ToString(); + dataObject["StartTime"] = eventArgs.Result.StartTimeUtc; + dataObject["EndTime"] = eventArgs.Result.EndTimeUtc; + dataObject["ResultErrorMessage"] = eventArgs.Result.ErrorMessage; + dataObject["ResultLongErrorMessage"] = eventArgs.Result.LongErrorMessage; - /// - public async Task OnEvent(TaskCompletionEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.TaskCompleted); - dataObject["TaskId"] = eventArgs.Task.Id; - dataObject["TaskName"] = eventArgs.Task.Name; - dataObject["TaskDescription"] = eventArgs.Task.Description; - dataObject["TaskCategory"] = eventArgs.Task.Category; - dataObject["TaskState"] = eventArgs.Task.State.ToString(); - dataObject["ResultId"] = eventArgs.Result.Id; - dataObject["ResultKey"] = eventArgs.Result.Key; - dataObject["ResultName"] = eventArgs.Result.Name; - dataObject["ResultStatus"] = eventArgs.Result.Status.ToString(); - dataObject["StartTime"] = eventArgs.Result.StartTimeUtc; - dataObject["EndTime"] = eventArgs.Result.EndTimeUtc; - dataObject["ResultErrorMessage"] = eventArgs.Result.ErrorMessage; - dataObject["ResultLongErrorMessage"] = eventArgs.Result.LongErrorMessage; - - await _webhookSender.SendNotification(NotificationType.TaskCompleted, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.TaskCompleted, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/UserCreatedNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/UserCreatedNotifier.cs index aa8c680..5b80bba 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/UserCreatedNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/UserCreatedNotifier.cs @@ -5,38 +5,37 @@ using Jellyfin.Plugin.Webhook.Helpers; using MediaBrowser.Controller; using MediaBrowser.Controller.Events; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// User created notifier. +/// +public class UserCreatedNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// User created notifier. + /// Initializes a new instance of the class. /// - public class UserCreatedNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public UserCreatedNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public UserCreatedNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(UserCreatedEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.UserCreated) + .AddUserData(eventArgs.Argument); - /// - public async Task OnEvent(UserCreatedEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.UserCreated) - .AddUserData(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.UserCreated, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.UserCreated, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/UserDataSavedNotifier/UserDataSavedNotifierEntryPoint.cs b/Jellyfin.Plugin.Webhook/Notifiers/UserDataSavedNotifier/UserDataSavedNotifierEntryPoint.cs index 3bfeda5..57910ad 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/UserDataSavedNotifier/UserDataSavedNotifierEntryPoint.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/UserDataSavedNotifier/UserDataSavedNotifierEntryPoint.cs @@ -7,104 +7,103 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook.Notifiers.UserDataSavedNotifier +namespace Jellyfin.Plugin.Webhook.Notifiers.UserDataSavedNotifier; + +/// +/// User data saved notifier. +/// +public class UserDataSavedNotifierEntryPoint : IServerEntryPoint { + private readonly IWebhookSender _webhookSender; + private readonly IServerApplicationHost _applicationHost; + private readonly IUserDataManager _userDataManager; + private readonly IUserManager _userManager; + private readonly ILogger _logger; + /// - /// User data saved notifier. + /// Initializes a new instance of the class. /// - public class UserDataSavedNotifierEntryPoint : IServerEntryPoint + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public UserDataSavedNotifierEntryPoint( + IWebhookSender webhookSender, + IServerApplicationHost applicationHost, + IUserDataManager userDataManager, + ILogger logger, + IUserManager userManager) { - private readonly IWebhookSender _webhookSender; - private readonly IServerApplicationHost _applicationHost; - private readonly IUserDataManager _userDataManager; - private readonly IUserManager _userManager; - private readonly ILogger _logger; + _userDataManager = userDataManager; + _logger = logger; + _userManager = userManager; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - /// Instance of the interface. - /// Instance of the interface. - /// Instance of the interface. - public UserDataSavedNotifierEntryPoint( - IWebhookSender webhookSender, - IServerApplicationHost applicationHost, - IUserDataManager userDataManager, - ILogger logger, - IUserManager userManager) + /// + public Task RunAsync() + { + _userDataManager.UserDataSaved += UserDataSavedHandler; + return Task.CompletedTask; + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose. + /// + /// Dispose all assets. + protected virtual void Dispose(bool disposing) + { + if (disposing) { - _userDataManager = userDataManager; - _logger = logger; - _userManager = userManager; - _applicationHost = applicationHost; - _webhookSender = webhookSender; + _userDataManager.UserDataSaved -= UserDataSavedHandler; } + } - /// - public Task RunAsync() + private async void UserDataSavedHandler(object? sender, UserDataSaveEventArgs eventArgs) + { + try { - _userDataManager.UserDataSaved += UserDataSavedHandler; - return Task.CompletedTask; - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Dispose. - /// - /// Dispose all assets. - protected virtual void Dispose(bool disposing) - { - if (disposing) + if (eventArgs.Item is null) { - _userDataManager.UserDataSaved -= UserDataSavedHandler; + return; } + + if (eventArgs.Item.IsThemeMedia) + { + // Don't report theme song or local trailer playback. + return; + } + + var user = _userManager.GetUserById(eventArgs.UserId); + if (user is null) + { + return; + } + + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.UserDataSaved) + .AddBaseItemData(eventArgs.Item) + .AddUserItemData(eventArgs.UserData); + + dataObject["SaveReason"] = eventArgs.SaveReason.ToString(); + dataObject["NotificationUsername"] = user.Username; + dataObject["UserId"] = user.Id; + + await _webhookSender.SendNotification(NotificationType.UserDataSaved, dataObject, eventArgs.Item.GetType()) + .ConfigureAwait(false); } - - private async void UserDataSavedHandler(object? sender, UserDataSaveEventArgs eventArgs) + catch (Exception ex) { - try - { - if (eventArgs.Item is null) - { - return; - } - - if (eventArgs.Item.IsThemeMedia) - { - // Don't report theme song or local trailer playback. - return; - } - - var user = _userManager.GetUserById(eventArgs.UserId); - if (user is null) - { - return; - } - - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.UserDataSaved) - .AddBaseItemData(eventArgs.Item) - .AddUserItemData(eventArgs.UserData); - - dataObject["SaveReason"] = eventArgs.SaveReason.ToString(); - dataObject["NotificationUsername"] = user.Username; - dataObject["UserId"] = user.Id; - - await _webhookSender.SendNotification(NotificationType.UserDataSaved, dataObject, eventArgs.Item.GetType()) - .ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Unable to send notification"); - } + _logger.LogWarning(ex, "Unable to send notification"); } } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/UserDeletedNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/UserDeletedNotifier.cs index be3ad48..399f458 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/UserDeletedNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/UserDeletedNotifier.cs @@ -5,38 +5,37 @@ using Jellyfin.Plugin.Webhook.Helpers; using MediaBrowser.Controller; using MediaBrowser.Controller.Events; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// User deleted notifier. +/// +public class UserDeletedNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// User deleted notifier. + /// Initializes a new instance of the class. /// - public class UserDeletedNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public UserDeletedNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public UserDeletedNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(UserDeletedEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.UserDeleted) + .AddUserData(eventArgs.Argument); - /// - public async Task OnEvent(UserDeletedEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.UserDeleted) - .AddUserData(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.UserDeleted, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.UserDeleted, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/UserLockedOutNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/UserLockedOutNotifier.cs index c1adaa1..16aad2f 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/UserLockedOutNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/UserLockedOutNotifier.cs @@ -5,38 +5,37 @@ using Jellyfin.Plugin.Webhook.Helpers; using MediaBrowser.Controller; using MediaBrowser.Controller.Events; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// User locked out notifier. +/// +public class UserLockedOutNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// User locked out notifier. + /// Initializes a new instance of the class. /// - public class UserLockedOutNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public UserLockedOutNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public UserLockedOutNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(UserLockedOutEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.UserLockedOut) + .AddUserData(eventArgs.Argument); - /// - public async Task OnEvent(UserLockedOutEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.UserLockedOut) - .AddUserData(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.UserLockedOut, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.UserLockedOut, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/UserPasswordChangedNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/UserPasswordChangedNotifier.cs index ad1c671..adee636 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/UserPasswordChangedNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/UserPasswordChangedNotifier.cs @@ -5,38 +5,37 @@ using Jellyfin.Plugin.Webhook.Helpers; using MediaBrowser.Controller; using MediaBrowser.Controller.Events; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// User password changed notifier. +/// +public class UserPasswordChangedNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// User password changed notifier. + /// Initializes a new instance of the class. /// - public class UserPasswordChangedNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public UserPasswordChangedNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public UserPasswordChangedNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(UserPasswordChangedEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.UserPasswordChanged) + .AddUserData(eventArgs.Argument); - /// - public async Task OnEvent(UserPasswordChangedEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.UserPasswordChanged) - .AddUserData(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.UserPasswordChanged, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.UserPasswordChanged, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/Notifiers/UserUpdatedNotifier.cs b/Jellyfin.Plugin.Webhook/Notifiers/UserUpdatedNotifier.cs index 922acab..8a19f20 100644 --- a/Jellyfin.Plugin.Webhook/Notifiers/UserUpdatedNotifier.cs +++ b/Jellyfin.Plugin.Webhook/Notifiers/UserUpdatedNotifier.cs @@ -5,38 +5,37 @@ using Jellyfin.Plugin.Webhook.Helpers; using MediaBrowser.Controller; using MediaBrowser.Controller.Events; -namespace Jellyfin.Plugin.Webhook.Notifiers +namespace Jellyfin.Plugin.Webhook.Notifiers; + +/// +/// User updated notifier. +/// +public class UserUpdatedNotifier : IEventConsumer { + private readonly IServerApplicationHost _applicationHost; + private readonly IWebhookSender _webhookSender; + /// - /// User updated notifier. + /// Initializes a new instance of the class. /// - public class UserUpdatedNotifier : IEventConsumer + /// Instance of the interface. + /// Instance of the interface. + public UserUpdatedNotifier( + IServerApplicationHost applicationHost, + IWebhookSender webhookSender) { - private readonly IServerApplicationHost _applicationHost; - private readonly IWebhookSender _webhookSender; + _applicationHost = applicationHost; + _webhookSender = webhookSender; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public UserUpdatedNotifier( - IServerApplicationHost applicationHost, - IWebhookSender webhookSender) - { - _applicationHost = applicationHost; - _webhookSender = webhookSender; - } + /// + public async Task OnEvent(UserUpdatedEventArgs eventArgs) + { + var dataObject = DataObjectHelpers + .GetBaseDataObject(_applicationHost, NotificationType.UserUpdated) + .AddUserData(eventArgs.Argument); - /// - public async Task OnEvent(UserUpdatedEventArgs eventArgs) - { - var dataObject = DataObjectHelpers - .GetBaseDataObject(_applicationHost, NotificationType.UserUpdated) - .AddUserData(eventArgs.Argument); - - await _webhookSender.SendNotification(NotificationType.UserUpdated, dataObject) - .ConfigureAwait(false); - } + await _webhookSender.SendNotification(NotificationType.UserUpdated, dataObject) + .ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs b/Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs index 4bcdebd..5e2f773 100644 --- a/Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs +++ b/Jellyfin.Plugin.Webhook/PluginServiceRegistrator.cs @@ -25,65 +25,64 @@ using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.DependencyInjection; -namespace Jellyfin.Plugin.Webhook +namespace Jellyfin.Plugin.Webhook; + +/// +/// Register webhook services. +/// +public class PluginServiceRegistrator : IPluginServiceRegistrator { - /// - /// Register webhook services. - /// - public class PluginServiceRegistrator : IPluginServiceRegistrator + /// + public void RegisterServices(IServiceCollection serviceCollection) { - /// - public void RegisterServices(IServiceCollection serviceCollection) - { - serviceCollection.AddScoped, DiscordClient>(); - serviceCollection.AddScoped, GenericClient>(); - serviceCollection.AddScoped, GenericFormClient>(); - serviceCollection.AddScoped, GotifyClient>(); - serviceCollection.AddScoped, PushbulletClient>(); - serviceCollection.AddScoped, PushoverClient>(); - serviceCollection.AddScoped, SlackClient>(); - serviceCollection.AddScoped, SmtpClient>(); - serviceCollection.AddScoped, MqttClient>(); + serviceCollection.AddScoped, DiscordClient>(); + serviceCollection.AddScoped, GenericClient>(); + serviceCollection.AddScoped, GenericFormClient>(); + serviceCollection.AddScoped, GotifyClient>(); + serviceCollection.AddScoped, PushbulletClient>(); + serviceCollection.AddScoped, PushoverClient>(); + serviceCollection.AddScoped, SlackClient>(); + serviceCollection.AddScoped, SmtpClient>(); + serviceCollection.AddScoped, MqttClient>(); - // Register sender. - serviceCollection.AddScoped(); + // Register sender. + serviceCollection.AddScoped(); - // Register MqttClients - serviceCollection.AddSingleton(); + // Register MqttClients + serviceCollection.AddSingleton(); - /*-- Register event consumers. --*/ - // Library consumers. - serviceCollection.AddScoped, SubtitleDownloadFailureNotifier>(); - serviceCollection.AddSingleton(); + /*-- Register event consumers. --*/ + // Library consumers. + serviceCollection.AddScoped, SubtitleDownloadFailureNotifier>(); + serviceCollection.AddSingleton(); - // Security consumers. - serviceCollection.AddScoped>, AuthenticationFailureNotifier>(); - serviceCollection.AddScoped>, AuthenticationSuccessNotifier>(); + // Security consumers. + serviceCollection.AddScoped>, AuthenticationFailureNotifier>(); + serviceCollection.AddScoped>, AuthenticationSuccessNotifier>(); - // Session consumers. - serviceCollection.AddScoped, PlaybackStartNotifier>(); - serviceCollection.AddScoped, PlaybackStopNotifier>(); - serviceCollection.AddScoped, PlaybackProgressNotifier>(); - serviceCollection.AddScoped, SessionStartNotifier>(); + // Session consumers. + serviceCollection.AddScoped, PlaybackStartNotifier>(); + serviceCollection.AddScoped, PlaybackStopNotifier>(); + serviceCollection.AddScoped, PlaybackProgressNotifier>(); + serviceCollection.AddScoped, SessionStartNotifier>(); - // System consumers. - serviceCollection.AddScoped, PendingRestartNotifier>(); - serviceCollection.AddScoped, TaskCompletedNotifier>(); + // System consumers. + serviceCollection.AddScoped, PendingRestartNotifier>(); + serviceCollection.AddScoped, TaskCompletedNotifier>(); - // Update consumers. - serviceCollection.AddScoped, PluginInstallationCancelledNotifier>(); - serviceCollection.AddScoped, PluginInstallationFailedNotifier>(); - serviceCollection.AddScoped, PluginInstalledNotifier>(); - serviceCollection.AddScoped, PluginInstallingNotifier>(); - serviceCollection.AddScoped, PluginUninstalledNotifier>(); - serviceCollection.AddScoped, PluginUpdatedNotifier>(); + // Update consumers. + serviceCollection.AddScoped, PluginInstallationCancelledNotifier>(); + serviceCollection.AddScoped, PluginInstallationFailedNotifier>(); + serviceCollection.AddScoped, PluginInstalledNotifier>(); + serviceCollection.AddScoped, PluginInstallingNotifier>(); + serviceCollection.AddScoped, PluginUninstalledNotifier>(); + serviceCollection.AddScoped, PluginUpdatedNotifier>(); - // User consumers. - serviceCollection.AddScoped, UserCreatedNotifier>(); - serviceCollection.AddScoped, UserDeletedNotifier>(); - serviceCollection.AddScoped, UserLockedOutNotifier>(); - serviceCollection.AddScoped, UserPasswordChangedNotifier>(); - serviceCollection.AddScoped, UserUpdatedNotifier>(); - } + // User consumers. + serviceCollection.AddScoped, UserCreatedNotifier>(); + serviceCollection.AddScoped, UserDeletedNotifier>(); + serviceCollection.AddScoped, UserLockedOutNotifier>(); + serviceCollection.AddScoped, UserPasswordChangedNotifier>(); + serviceCollection.AddScoped, UserUpdatedNotifier>(); } } diff --git a/Jellyfin.Plugin.Webhook/WebhookPlugin.cs b/Jellyfin.Plugin.Webhook/WebhookPlugin.cs index b765761..5310f81 100644 --- a/Jellyfin.Plugin.Webhook/WebhookPlugin.cs +++ b/Jellyfin.Plugin.Webhook/WebhookPlugin.cs @@ -6,55 +6,54 @@ using MediaBrowser.Common.Plugins; using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Serialization; -namespace Jellyfin.Plugin.Webhook +namespace Jellyfin.Plugin.Webhook; + +/// +/// Plugin entrypoint. +/// +public class WebhookPlugin : BasePlugin, IHasWebPages { + private readonly Guid _id = new("71552A5A-5C5C-4350-A2AE-EBE451A30173"); + /// - /// Plugin entrypoint. + /// Initializes a new instance of the class. /// - public class WebhookPlugin : BasePlugin, IHasWebPages + /// Instance of the interface. + /// Instance of the interface. + public WebhookPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) + : base(applicationPaths, xmlSerializer) { - private readonly Guid _id = new ("71552A5A-5C5C-4350-A2AE-EBE451A30173"); + Instance = this; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public WebhookPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) - : base(applicationPaths, xmlSerializer) + /// + /// Gets current plugin instance. + /// + public static WebhookPlugin? Instance { get; private set; } + + /// + public override Guid Id => _id; + + /// + public override string Name => "Webhook"; + + /// + public override string Description => "Sends notifications to various services via webhooks."; + + /// + public IEnumerable GetPages() + { + var prefix = GetType().Namespace; + yield return new PluginPageInfo { - Instance = this; - } + Name = Name, + EmbeddedResourcePath = prefix + ".Configuration.Web.config.html" + }; - /// - /// Gets current plugin instance. - /// - public static WebhookPlugin? Instance { get; private set; } - - /// - public override Guid Id => _id; - - /// - public override string Name => "Webhook"; - - /// - public override string Description => "Sends notifications to various services via webhooks."; - - /// - public IEnumerable GetPages() + yield return new PluginPageInfo { - var prefix = GetType().Namespace; - yield return new PluginPageInfo - { - Name = Name, - EmbeddedResourcePath = prefix + ".Configuration.Web.config.html" - }; - - yield return new PluginPageInfo - { - Name = $"{Name}.js", - EmbeddedResourcePath = prefix + ".Configuration.Web.config.js" - }; - } + Name = $"{Name}.js", + EmbeddedResourcePath = prefix + ".Configuration.Web.config.js" + }; } } diff --git a/Jellyfin.Plugin.Webhook/WebhookSender.cs b/Jellyfin.Plugin.Webhook/WebhookSender.cs index aa56fae..c94b8e4 100644 --- a/Jellyfin.Plugin.Webhook/WebhookSender.cs +++ b/Jellyfin.Plugin.Webhook/WebhookSender.cs @@ -18,175 +18,174 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.Webhook +namespace Jellyfin.Plugin.Webhook; + +/// +public class WebhookSender : IWebhookSender { - /// - public class WebhookSender : IWebhookSender + private readonly ILogger _logger; + private readonly IWebhookClient _discordClient; + private readonly IWebhookClient _genericClient; + private readonly IWebhookClient _genericFormClient; + private readonly IWebhookClient _gotifyClient; + private readonly IWebhookClient _pushbulletClient; + private readonly IWebhookClient _pushoverClient; + private readonly IWebhookClient _slackClient; + private readonly IWebhookClient _smtpClient; + private readonly IWebhookClient _mqttClient; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of . + /// /// Instance of the . + /// Instance of the . + /// Instance of . + /// Instance of the . + /// Instance of the . + /// Instance of the . + /// Instance of the . + /// Instance of the . + public WebhookSender( + ILogger logger, + IWebhookClient discordClient, + IWebhookClient genericClient, + IWebhookClient genericFormClient, + IWebhookClient gotifyClient, + IWebhookClient pushbulletClient, + IWebhookClient pushoverClient, + IWebhookClient slackClient, + IWebhookClient smtpClient, + IWebhookClient mqttClient) { - private readonly ILogger _logger; - private readonly IWebhookClient _discordClient; - private readonly IWebhookClient _genericClient; - private readonly IWebhookClient _genericFormClient; - private readonly IWebhookClient _gotifyClient; - private readonly IWebhookClient _pushbulletClient; - private readonly IWebhookClient _pushoverClient; - private readonly IWebhookClient _slackClient; - private readonly IWebhookClient _smtpClient; - private readonly IWebhookClient _mqttClient; + _logger = logger; + _discordClient = discordClient; + _genericClient = genericClient; + _genericFormClient = genericFormClient; + _gotifyClient = gotifyClient; + _pushbulletClient = pushbulletClient; + _pushoverClient = pushoverClient; + _slackClient = slackClient; + _smtpClient = smtpClient; + _mqttClient = mqttClient; + } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of . - /// /// Instance of the . - /// Instance of the . - /// Instance of . - /// Instance of the . - /// Instance of the . - /// Instance of the . - /// Instance of the . - /// Instance of the . - public WebhookSender( - ILogger logger, - IWebhookClient discordClient, - IWebhookClient genericClient, - IWebhookClient genericFormClient, - IWebhookClient gotifyClient, - IWebhookClient pushbulletClient, - IWebhookClient pushoverClient, - IWebhookClient slackClient, - IWebhookClient smtpClient, - IWebhookClient mqttClient) + private static PluginConfiguration Configuration => + WebhookPlugin.Instance!.Configuration; + + /// + public async Task SendNotification(NotificationType notificationType, Dictionary itemData, Type? itemType = null) + { + foreach (var option in Configuration.DiscordOptions.Where(o => o.NotificationTypes.Contains(notificationType))) { - _logger = logger; - _discordClient = discordClient; - _genericClient = genericClient; - _genericFormClient = genericFormClient; - _gotifyClient = gotifyClient; - _pushbulletClient = pushbulletClient; - _pushoverClient = pushoverClient; - _slackClient = slackClient; - _smtpClient = smtpClient; - _mqttClient = mqttClient; + await SendNotification(_discordClient, option, itemData, itemType) + .ConfigureAwait(false); } - private static PluginConfiguration Configuration => - WebhookPlugin.Instance!.Configuration; - - /// - public async Task SendNotification(NotificationType notificationType, Dictionary itemData, Type? itemType = null) + foreach (var option in Configuration.GenericOptions.Where(o => o.NotificationTypes.Contains(notificationType))) { - foreach (var option in Configuration.DiscordOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_discordClient, option, itemData, itemType) - .ConfigureAwait(false); - } - - foreach (var option in Configuration.GenericOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_genericClient, option, itemData, itemType) - .ConfigureAwait(false); - } - - foreach (var option in Configuration.GenericFormOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_genericFormClient, option, itemData, itemType) - .ConfigureAwait(false); - } - - foreach (var option in Configuration.GotifyOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_gotifyClient, option, itemData, itemType) - .ConfigureAwait(false); - } - - foreach (var option in Configuration.PushbulletOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_pushbulletClient, option, itemData, itemType) - .ConfigureAwait(false); - } - - foreach (var option in Configuration.PushoverOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_pushoverClient, option, itemData, itemType) - .ConfigureAwait(false); - } - - foreach (var option in Configuration.SlackOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_slackClient, option, itemData, itemType) - .ConfigureAwait(false); - } - - foreach (var option in Configuration.SmtpOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_smtpClient, option, itemData, itemType) - .ConfigureAwait(false); - } - - foreach (var option in Configuration.MqttOptions.Where(o => o.NotificationTypes.Contains(notificationType))) - { - await SendNotification(_mqttClient, option, itemData, itemType) - .ConfigureAwait(false); - } + await SendNotification(_genericClient, option, itemData, itemType) + .ConfigureAwait(false); } - private static bool NotifyOnItem(T baseOptions, Type? itemType) - where T : BaseOption + foreach (var option in Configuration.GenericFormOptions.Where(o => o.NotificationTypes.Contains(notificationType))) { - if (itemType is null) - { - return true; - } - - if (baseOptions.EnableAlbums && itemType == typeof(MusicAlbum)) - { - return true; - } - - if (baseOptions.EnableMovies && itemType == typeof(Movie)) - { - return true; - } - - if (baseOptions.EnableEpisodes && itemType == typeof(Episode)) - { - return true; - } - - if (baseOptions.EnableSeries && itemType == typeof(Series)) - { - return true; - } - - if (baseOptions.EnableSeasons && itemType == typeof(Season)) - { - return true; - } - - if (baseOptions.EnableSongs && itemType == typeof(Audio)) - { - return true; - } - - return false; + await SendNotification(_genericFormClient, option, itemData, itemType) + .ConfigureAwait(false); } - private async Task SendNotification(IWebhookClient webhookClient, T option, Dictionary itemData, Type? itemType) - where T : BaseOption + foreach (var option in Configuration.GotifyOptions.Where(o => o.NotificationTypes.Contains(notificationType))) { - if (NotifyOnItem(option, itemType)) + await SendNotification(_gotifyClient, option, itemData, itemType) + .ConfigureAwait(false); + } + + foreach (var option in Configuration.PushbulletOptions.Where(o => o.NotificationTypes.Contains(notificationType))) + { + await SendNotification(_pushbulletClient, option, itemData, itemType) + .ConfigureAwait(false); + } + + foreach (var option in Configuration.PushoverOptions.Where(o => o.NotificationTypes.Contains(notificationType))) + { + await SendNotification(_pushoverClient, option, itemData, itemType) + .ConfigureAwait(false); + } + + foreach (var option in Configuration.SlackOptions.Where(o => o.NotificationTypes.Contains(notificationType))) + { + await SendNotification(_slackClient, option, itemData, itemType) + .ConfigureAwait(false); + } + + foreach (var option in Configuration.SmtpOptions.Where(o => o.NotificationTypes.Contains(notificationType))) + { + await SendNotification(_smtpClient, option, itemData, itemType) + .ConfigureAwait(false); + } + + foreach (var option in Configuration.MqttOptions.Where(o => o.NotificationTypes.Contains(notificationType))) + { + await SendNotification(_mqttClient, option, itemData, itemType) + .ConfigureAwait(false); + } + } + + private static bool NotifyOnItem(T baseOptions, Type? itemType) + where T : BaseOption + { + if (itemType is null) + { + return true; + } + + if (baseOptions.EnableAlbums && itemType == typeof(MusicAlbum)) + { + return true; + } + + if (baseOptions.EnableMovies && itemType == typeof(Movie)) + { + return true; + } + + if (baseOptions.EnableEpisodes && itemType == typeof(Episode)) + { + return true; + } + + if (baseOptions.EnableSeries && itemType == typeof(Series)) + { + return true; + } + + if (baseOptions.EnableSeasons && itemType == typeof(Season)) + { + return true; + } + + if (baseOptions.EnableSongs && itemType == typeof(Audio)) + { + return true; + } + + return false; + } + + private async Task SendNotification(IWebhookClient webhookClient, T option, Dictionary itemData, Type? itemType) + where T : BaseOption + { + if (NotifyOnItem(option, itemType)) + { + try { - try - { - await webhookClient.SendAsync(option, itemData) - .ConfigureAwait(false); - } - catch (Exception e) - { - _logger.LogError(e, "Unable to send notification"); - } + await webhookClient.SendAsync(option, itemData) + .ConfigureAwait(false); + } + catch (Exception e) + { + _logger.LogError(e, "Unable to send notification"); } } } diff --git a/Jellyfin.Plugin.Webhook/WebhookServerEntryPoint.cs b/Jellyfin.Plugin.Webhook/WebhookServerEntryPoint.cs index ac79afe..2429b43 100644 --- a/Jellyfin.Plugin.Webhook/WebhookServerEntryPoint.cs +++ b/Jellyfin.Plugin.Webhook/WebhookServerEntryPoint.cs @@ -58,4 +58,4 @@ public class WebhookServerEntryPoint : IServerEntryPoint { await _mqttClients.UpdateClients(Configuration.MqttOptions).ConfigureAwait(false); } -} \ No newline at end of file +}