Merge pull request #15 from crobibero/send-all-props

This commit is contained in:
Cody Robibero 2021-03-13 14:55:33 -07:00 committed by GitHub
commit 428209036d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 216 additions and 126 deletions

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
using System.Net.Mime;
@ -31,6 +32,11 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Discord
{
try
{
if (string.IsNullOrEmpty(options.WebhookUri))
{
throw new ArgumentException(nameof(options.WebhookUri));
}
// Add discord specific properties.
data["MentionType"] = GetMentionType(options.MentionType);
if (!string.IsNullOrEmpty(options.EmbedColor))
@ -53,10 +59,12 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Discord
using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json);
using var response = await _httpClientFactory
.CreateClient(NamedClient.Default)
.PostAsync(options.WebhookUri, content);
.PostAsync(new Uri(options.WebhookUri), content)
.ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var responseStr = await response.Content.ReadAsStringAsync();
var responseStr = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
_logger.LogWarning("Error sending notification: {Response}", responseStr);
}
}

View File

@ -70,10 +70,12 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Generic
httpRequestMessage.Content = new StringContent(body, Encoding.UTF8, contentType);
using var response = await _httpClientFactory
.CreateClient(NamedClient.Default)
.SendAsync(httpRequestMessage);
.SendAsync(httpRequestMessage)
.ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var responseStr = await response.Content.ReadAsStringAsync();
var responseStr = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
_logger.LogWarning("Error sending notification: {Response}", responseStr);
}
}

View File

@ -33,7 +33,7 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Gotify
{
if (string.IsNullOrEmpty(options.WebhookUri))
{
throw new NullReferenceException(nameof(options.WebhookUri));
throw new ArgumentException(nameof(options.WebhookUri));
}
// Add gotify specific properties.
@ -44,10 +44,12 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Gotify
using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json);
using var response = await _httpClientFactory
.CreateClient(NamedClient.Default)
.PostAsync(options.WebhookUri.TrimEnd() + $"/message?token={options.Token}", content);
.PostAsync(new Uri(options.WebhookUri.TrimEnd() + $"/message?token={options.Token}"), content)
.ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var responseStr = await response.Content.ReadAsStringAsync();
var responseStr = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
_logger.LogWarning("Error sending notification: {Response}", responseStr);
}
}

View File

@ -5,6 +5,11 @@
/// </summary>
public enum NotificationType
{
/// <summary>
/// No notification type.
/// </summary>
None = 0,
/// <summary>
/// Item added notification.
/// </summary>

View File

@ -45,10 +45,12 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Pushbullet
using var response = await _httpClientFactory
.CreateClient(NamedClient.Default)
.SendAsync(requestOptions);
.SendAsync(requestOptions)
.ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var responseStr = await response.Content.ReadAsStringAsync();
var responseStr = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
_logger.LogWarning("Error sending notification: {Response}", responseStr);
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
@ -52,7 +53,7 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Pushover
data["MessageUrlTitle"] = options.MessageUrlTitle;
}
if (options.MessagePriority.HasValue)
if (options.MessagePriority is not null)
{
data["MessagePriority"] = options.MessagePriority;
}
@ -67,10 +68,12 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Pushover
using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json);
using var response = await _httpClientFactory
.CreateClient(NamedClient.Default)
.PostAsync(string.IsNullOrEmpty(options.WebhookUri) ? PushoverOption.ApiUrl : options.WebhookUri, content);
.PostAsync(string.IsNullOrEmpty(options.WebhookUri) ? PushoverOption.ApiUrl : new Uri(options.WebhookUri), content)
.ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var responseStr = await response.Content.ReadAsStringAsync();
var responseStr = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
_logger.LogWarning("Error sending notification: {Response}", responseStr);
}
}

View File

@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using System;
using System.Text.Json.Serialization;
namespace Jellyfin.Plugin.Webhook.Destinations.Pushover
{
@ -11,7 +12,7 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Pushover
/// The webhook endpoint.
/// </summary>
[JsonIgnore]
public const string ApiUrl = "https://api.pushover.net/1/messages.json";
public static readonly Uri ApiUrl = new Uri("https://api.pushover.net/1/messages.json");
/// <summary>
/// Gets or sets the pushover token.

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
@ -30,6 +31,11 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Slack
{
try
{
if (string.IsNullOrEmpty(options.WebhookUri))
{
throw new ArgumentException(nameof(options.WebhookUri));
}
data["SlackUsername"] = options.Username;
data["SlackIconUrl"] = options.IconUrl;
@ -38,10 +44,12 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Slack
using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json);
using var response = await _httpClientFactory
.CreateClient(NamedClient.Default)
.PostAsync(options.WebhookUri, content);
.PostAsync(new Uri(options.WebhookUri), content)
.ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var responseStr = await response.Content.ReadAsStringAsync();
var responseStr = await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
_logger.LogWarning("Error sending notification: {Response}", responseStr);
}
}

View File

@ -29,20 +29,23 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Smtp
message.From.Add(new MailboxAddress(options.SenderAddress, options.SenderAddress));
message.To.Add(new MailboxAddress(options.ReceiverAddress, options.ReceiverAddress));
message.Subject = options.GetSubjectTemplate()(data);
message.Subject = options.GetCompiledSubjectTemplate()(data);
message.Body = new TextPart(options.IsHtml ? "html" : "plain")
{
Text = options.GetMessageBody(data)
};
using var smtpClient = new MailKit.Net.Smtp.SmtpClient();
await smtpClient.ConnectAsync(options.SmtpServer, options.SmtpPort, options.UseSsl);
await smtpClient.ConnectAsync(options.SmtpServer, options.SmtpPort, options.UseSsl)
.ConfigureAwait(false);
if (options.UseCredentials)
{
await smtpClient.AuthenticateAsync(options.Username, options.Password);
await smtpClient.AuthenticateAsync(options.Username, options.Password)
.ConfigureAwait(false);
}
await smtpClient.SendAsync(message);
await smtpClient.SendAsync(message)
.ConfigureAwait(false);
}
catch (Exception e)
{

View File

@ -64,7 +64,7 @@ namespace Jellyfin.Plugin.Webhook.Destinations.Smtp
/// Gets the compiled handlebars subject template.
/// </summary>
/// <returns>The compiled handlebars subject template.</returns>
public HandlebarsTemplate<object, string> GetSubjectTemplate()
public HandlebarsTemplate<object, string> GetCompiledSubjectTemplate()
{
return _compiledSubjectTemplate ??= Handlebars.Compile(HandlebarsFunctionHelpers.Base64Decode(SubjectTemplate));
}

View File

@ -5,6 +5,7 @@ using Jellyfin.Data.Entities;
using Jellyfin.Plugin.Webhook.Destinations;
using MediaBrowser.Common;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Session;
@ -44,7 +45,7 @@ namespace Jellyfin.Plugin.Webhook.Helpers
/// <returns>The data object.</returns>
public static Dictionary<string, object> AddBaseItemData(this Dictionary<string, object> dataObject, BaseItem? item)
{
if (item == null)
if (item is null)
{
return dataObject;
}
@ -56,56 +57,96 @@ namespace Jellyfin.Plugin.Webhook.Helpers
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.HasValue)
if (item.ProductionYear is not null)
{
dataObject["Year"] = item.ProductionYear;
}
switch (item)
{
case Season:
if (!string.IsNullOrEmpty(item.Parent?.Name))
case Season season:
if (!string.IsNullOrEmpty(season.Series?.Name))
{
dataObject["SeriesName"] = item.Parent.Name.Escape();
dataObject["SeriesName"] = season.Series.Name.Escape();
}
if (item.Parent?.ProductionYear != null)
if (season.Series?.ProductionYear is not null)
{
dataObject["Year"] = item.Parent.ProductionYear;
dataObject["Year"] = season.Series.ProductionYear;
}
if (item.IndexNumber.HasValue)
if (season.IndexNumber is not null)
{
dataObject["SeasonNumber"] = item.IndexNumber;
dataObject["SeasonNumber00"] = item.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
dataObject["SeasonNumber000"] = item.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
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:
if (!string.IsNullOrEmpty(item.Parent?.Parent?.Name))
case Episode episode:
if (!string.IsNullOrEmpty(episode.Series?.Name))
{
dataObject["SeriesName"] = item.Parent.Parent.Name.Escape();
dataObject["SeriesName"] = episode.Series.Name.Escape();
}
if (item.Parent?.IndexNumber != null)
if (episode.Season?.IndexNumber is not null)
{
dataObject["SeasonNumber"] = item.Parent.IndexNumber;
dataObject["SeasonNumber00"] = item.Parent.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
dataObject["SeasonNumber000"] = item.Parent.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
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 (item.IndexNumber.HasValue)
if (episode.IndexNumber is not null)
{
dataObject["EpisodeNumber"] = item.IndexNumber;
dataObject["EpisodeNumber00"] = item.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
dataObject["EpisodeNumber000"] = item.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
dataObject["EpisodeNumber"] = episode.IndexNumber;
dataObject["EpisodeNumber00"] = episode.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
dataObject["EpisodeNumber000"] = episode.IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
}
if (item.Parent?.Parent?.ProductionYear != null)
if (episode.IndexNumberEnd is not null)
{
dataObject["Year"] = item.Parent.Parent.ProductionYear;
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;
@ -128,7 +169,7 @@ namespace Jellyfin.Plugin.Webhook.Helpers
public static Dictionary<string, object> AddPlaybackProgressData(this Dictionary<string, object> dataObject, PlaybackProgressEventArgs playbackProgressEventArgs)
{
dataObject[nameof(playbackProgressEventArgs.PlaybackPositionTicks)] = playbackProgressEventArgs.PlaybackPositionTicks ?? 0;
dataObject["PlaybackPosition"] = TimeSpan.FromTicks(playbackProgressEventArgs.PlaybackPositionTicks ?? 0).ToString(@"hh\:mm\:ss");
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;
@ -229,6 +270,6 @@ namespace Jellyfin.Plugin.Webhook.Helpers
/// <param name="input">Input string.</param>
/// <returns>Escaped string.</returns>
private static string Escape(this string? input)
=> input?.Replace("\"", "\\\"") ?? string.Empty;
=> input?.Replace("\"", "\\\"", StringComparison.Ordinal) ?? string.Empty;
}
}

View File

@ -1,32 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Jellyfin.Plugin.Webhook.Helpers
{
/// <summary>
/// Periodic async helper.
/// </summary>
public static class PeriodicAsyncHelper
{
/// <summary>
/// Runs an async function periodically.
/// </summary>
/// <param name="taskFactory">The task factory.</param>
/// <param name="interval">The run interval.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static async Task PeriodicAsync(
Func<Task> taskFactory,
TimeSpan interval,
CancellationToken cancellationToken = default)
{
while (!cancellationToken.IsCancellationRequested)
{
var delayTask = Task.Delay(interval, cancellationToken);
await taskFactory();
await delayTask;
}
}
}
}

View File

@ -7,11 +7,14 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
<NoWarn>CA1819</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Handlebars.Net" Version="2.0.4" />
<PackageReference Include="Jellyfin.Controller" Version="10.7.0-rc4" />
<PackageReference Include="Jellyfin.Controller" Version="10.7-*" />
</ItemGroup>
<ItemGroup>

View File

@ -32,7 +32,7 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
/// <inheritdoc />
public async Task OnEvent(GenericEventArgs<AuthenticationRequest> eventArgs)
{
if (eventArgs.Argument == null)
if (eventArgs.Argument is null)
{
return;
}
@ -46,7 +46,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
dataObject[nameof(eventArgs.Argument.DeviceId)] = eventArgs.Argument.DeviceId;
dataObject[nameof(eventArgs.Argument.DeviceName)] = eventArgs.Argument.DeviceName;
await _webhookSender.SendNotification(NotificationType.AuthenticationFailure, dataObject);
await _webhookSender.SendNotification(NotificationType.AuthenticationFailure, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -32,7 +32,7 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
/// <inheritdoc />
public async Task OnEvent(GenericEventArgs<AuthenticationResult> eventArgs)
{
if (eventArgs.Argument == null)
if (eventArgs.Argument is null)
{
return;
}
@ -41,7 +41,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.AuthenticationSuccess)
.AddUserData(eventArgs.Argument.User);
await _webhookSender.SendNotification(NotificationType.AuthenticationSuccess, dataObject);
await _webhookSender.SendNotification(NotificationType.AuthenticationSuccess, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -43,7 +43,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
dataObject[nameof(request.User.Username)] = request.User.Username;
dataObject["UserId"] = request.User.Id;
await _webhookSender.SendNotification(NotificationType.Generic, dataObject);
await _webhookSender.SendNotification(NotificationType.Generic, dataObject)
.ConfigureAwait(false);
}
/// <inheritdoc />

View File

@ -50,7 +50,7 @@ namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier
foreach (var (key, container) in currentItems)
{
var item = _libraryManager.GetItemById(key);
if (item == null)
if (item is null)
{
// Remove item from queue.
_itemProcessQueue.TryRemove(key, out _);
@ -76,7 +76,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier
.AddBaseItemData(item);
var itemType = item.GetType();
await _webhookSender.SendNotification(NotificationType.ItemAdded, dataObject, itemType);
await _webhookSender.SendNotification(NotificationType.ItemAdded, dataObject, itemType)
.ConfigureAwait(false);
// Remove item from queue.
_itemProcessQueue.TryRemove(key, out _);

View File

@ -34,7 +34,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
var dataObject = DataObjectHelpers
.GetBaseDataObject(_applicationHost, NotificationType.PendingRestart);
await _webhookSender.SendNotification(NotificationType.PendingRestart, dataObject);
await _webhookSender.SendNotification(NotificationType.PendingRestart, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -32,7 +32,7 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
/// <inheritdoc />
public async Task OnEvent(PlaybackProgressEventArgs eventArgs)
{
if (eventArgs.Item == null)
if (eventArgs.Item is null)
{
return;
}
@ -62,7 +62,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
["UserId"] = user.Id
};
await _webhookSender.SendNotification(NotificationType.PlaybackProgress, userDataObject, eventArgs.Item.GetType());
await _webhookSender.SendNotification(NotificationType.PlaybackProgress, userDataObject, eventArgs.Item.GetType())
.ConfigureAwait(false);
}
}
}

View File

@ -32,7 +32,7 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
/// <inheritdoc />
public async Task OnEvent(PlaybackStartEventArgs eventArgs)
{
if (eventArgs.Item == null)
if (eventArgs.Item is null)
{
return;
}
@ -62,7 +62,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
["UserId"] = user.Id
};
await _webhookSender.SendNotification(NotificationType.PlaybackStart, userDataObject, eventArgs.Item.GetType());
await _webhookSender.SendNotification(NotificationType.PlaybackStart, userDataObject, eventArgs.Item.GetType())
.ConfigureAwait(false);
}
}
}

View File

@ -32,7 +32,7 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
/// <inheritdoc />
public async Task OnEvent(PlaybackStopEventArgs eventArgs)
{
if (eventArgs.Item == null)
if (eventArgs.Item is null)
{
return;
}
@ -63,7 +63,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
["UserId"] = user.Id
};
await _webhookSender.SendNotification(NotificationType.PlaybackStop, userDataObject, eventArgs.Item.GetType());
await _webhookSender.SendNotification(NotificationType.PlaybackStop, userDataObject, eventArgs.Item.GetType())
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.PluginInstallationCancelled)
.AddPluginInstallationInfo(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.PluginInstallationCancelled, dataObject);
await _webhookSender.SendNotification(NotificationType.PluginInstallationCancelled, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -36,7 +36,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.AddPluginInstallationInfo(eventArgs.InstallationInfo)
.AddExceptionInfo(eventArgs.Exception);
await _webhookSender.SendNotification(NotificationType.PluginInstallationFailed, dataObject);
await _webhookSender.SendNotification(NotificationType.PluginInstallationFailed, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.PluginInstalled)
.AddPluginInstallationInfo(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.PluginInstalled, dataObject);
await _webhookSender.SendNotification(NotificationType.PluginInstalled, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.PluginInstalling)
.AddPluginInstallationInfo(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.PluginInstalling, dataObject);
await _webhookSender.SendNotification(NotificationType.PluginInstalling, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -39,7 +39,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
dataObject["PluginVersion"] = eventArgs.Argument.Version;
dataObject["PluginStatus"] = eventArgs.Argument.Status;
await _webhookSender.SendNotification(NotificationType.PluginUninstalled, dataObject);
await _webhookSender.SendNotification(NotificationType.PluginUninstalled, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.PluginUpdated)
.AddPluginInstallationInfo(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.PluginUpdated, dataObject);
await _webhookSender.SendNotification(NotificationType.PluginUpdated, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -31,7 +31,7 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
/// <inheritdoc />
public async Task OnEvent(SessionStartedEventArgs eventArgs)
{
if (eventArgs.Argument == null)
if (eventArgs.Argument is null)
{
return;
}
@ -41,7 +41,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.AddSessionInfoData(eventArgs.Argument)
.AddBaseItemData(eventArgs.Argument.FullNowPlayingItem);
await _webhookSender.SendNotification(NotificationType.SessionStart, dataObject);
await _webhookSender.SendNotification(NotificationType.SessionStart, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -31,7 +31,7 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
/// <inheritdoc />
public async Task OnEvent(SubtitleDownloadFailureEventArgs eventArgs)
{
if (eventArgs.Item == null)
if (eventArgs.Item is null)
{
return;
}
@ -39,7 +39,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
var dataObject = DataObjectHelpers
.GetBaseDataObject(_applicationHost, NotificationType.SubtitleDownloadFailure)
.AddBaseItemData(eventArgs.Item);
await _webhookSender.SendNotification(NotificationType.SubtitleDownloadFailure, dataObject, eventArgs.Item.GetType());
await _webhookSender.SendNotification(NotificationType.SubtitleDownloadFailure, dataObject, eventArgs.Item.GetType())
.ConfigureAwait(false);
}
}
}

View File

@ -47,7 +47,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
dataObject["ResultErrorMessage"] = eventArgs.Result.ErrorMessage;
dataObject["ResultLongErrorMessage"] = eventArgs.Result.LongErrorMessage;
await _webhookSender.SendNotification(NotificationType.TaskCompleted, dataObject);
await _webhookSender.SendNotification(NotificationType.TaskCompleted, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.UserCreated)
.AddUserData(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.UserCreated, dataObject);
await _webhookSender.SendNotification(NotificationType.UserCreated, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.UserDeleted)
.AddUserData(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.UserDeleted, dataObject);
await _webhookSender.SendNotification(NotificationType.UserDeleted, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.UserLockedOut)
.AddUserData(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.UserLockedOut, dataObject);
await _webhookSender.SendNotification(NotificationType.UserLockedOut, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.UserPasswordChanged)
.AddUserData(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.UserPasswordChanged, dataObject);
await _webhookSender.SendNotification(NotificationType.UserPasswordChanged, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -35,7 +35,8 @@ namespace Jellyfin.Plugin.Webhook.Notifiers
.GetBaseDataObject(_applicationHost, NotificationType.UserUpdated)
.AddUserData(eventArgs.Argument);
await _webhookSender.SendNotification(NotificationType.UserUpdated, dataObject);
await _webhookSender.SendNotification(NotificationType.UserUpdated, dataObject)
.ConfigureAwait(false);
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Jellyfin.Plugin.Webhook.Configuration;
using Jellyfin.Plugin.Webhook.Destinations;
@ -62,52 +63,58 @@ namespace Jellyfin.Plugin.Webhook
}
private static PluginConfiguration Configuration =>
WebhookPlugin.Instance?.Configuration
?? throw new NullReferenceException(nameof(WebhookPlugin.Instance.Configuration));
WebhookPlugin.Instance!.Configuration;
/// <inheritdoc />
public async Task SendNotification(NotificationType notificationType, Dictionary<string, object> itemData, Type? itemType = null)
{
foreach (var option in Configuration.DiscordOptions.Where(o => o.NotificationTypes.Contains(notificationType)))
{
await SendNotification(_discordClient, option, itemData, itemType);
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);
await SendNotification(_genericClient, option, itemData, itemType)
.ConfigureAwait(false);
}
foreach (var option in Configuration.GotifyOptions.Where(o => o.NotificationTypes.Contains(notificationType)))
{
await SendNotification(_gotifyClient, option, itemData, 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);
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);
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);
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);
await SendNotification(_smtpClient, option, itemData, itemType)
.ConfigureAwait(false);
}
}
private static bool NotifyOnItem<T>(T baseOptions, Type? itemType)
where T : BaseOption
{
if (itemType == null)
if (itemType is null)
{
return true;
}
@ -152,7 +159,8 @@ namespace Jellyfin.Plugin.Webhook
{
try
{
await webhookClient.SendAsync(option, itemData);
await webhookClient.SendAsync(option, itemData)
.ConfigureAwait(false);
}
catch (Exception e)
{

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Rules for Jellyfin.Server" Description="Code analysis rules for Jellyfin.Server.csproj" ToolsVersion="14.0">
<RuleSet Name="Rules for Jellyfin" Description="Code analysis rules for Jellyfin" ToolsVersion="14.0">
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<!-- disable warning SA1202: 'public' members must come before 'private' members -->
<Rule Id="SA1202" Action="Info" />
@ -10,6 +10,8 @@
<!-- disable warning SA1009: Closing parenthesis should be followed by a space. -->
<Rule Id="SA1009" Action="None" />
<!-- disable warning SA1011: Closing square bracket should be followed by a space. -->
<Rule Id="SA1011" Action="None" />
<!-- disable warning SA1101: Prefix local calls with 'this.' -->
<Rule Id="SA1101" Action="None" />
<!-- disable warning SA1108: Block statements should not contain embedded comments -->
@ -30,11 +32,17 @@
<Rule Id="SA1515" Action="None" />
<!-- disable warning SA1600: Elements should be documented -->
<Rule Id="SA1600" Action="None" />
<!-- disable warning SA1602: Enumeration items should be documented -->
<Rule Id="SA1602" Action="None" />
<!-- disable warning SA1633: The file header is missing or not located at the top of the file -->
<Rule Id="SA1633" Action="None" />
</Rules>
<Rules AnalyzerId="Microsoft.CodeAnalysis.FxCopAnalyzers" RuleNamespace="Microsoft.Design">
<Rules AnalyzerId="Microsoft.CodeAnalysis.NetAnalyzers" RuleNamespace="Microsoft.Design">
<!-- error on CA2016: Forward the CancellationToken parameter to methods that take one
or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token -->
<Rule Id="CA2016" Action="Error" />
<!-- disable warning CA1031: Do not catch general exception types -->
<Rule Id="CA1031" Action="Info" />
<!-- disable warning CA1032: Implement standard exception constructors -->
@ -45,6 +53,8 @@
<Rule Id="CA1716" Action="Info" />
<!-- disable warning CA1720: Identifiers should not contain type names -->
<Rule Id="CA1720" Action="Info" />
<!-- disable warning CA1805: Do not initialize unnecessarily -->
<Rule Id="CA1805" Action="Info" />
<!-- disable warning CA1812: internal class that is apparently never instantiated.
If so, remove the code from the assembly.
If this class is intended to contain only static members, make it static -->
@ -53,7 +63,11 @@
<Rule Id="CA1822" Action="Info" />
<!-- disable warning CA2000: Dispose objects before losing scope -->
<Rule Id="CA2000" Action="Info" />
<!-- disable warning CA5394: Do not use insecure randomness -->
<Rule Id="CA5394" Action="Info" />
<!-- disable warning CA1014: Mark assemblies with CLSCompliantAttribute -->
<Rule Id="CA1014" Action="Info" />
<!-- disable warning CA1054: Change the type of parameter url from string to System.Uri -->
<Rule Id="CA1054" Action="None" />
<!-- disable warning CA1055: URI return values should not be strings -->