mirror of
https://github.com/jellyfin/jellyfin-plugin-webhook.git
synced 2024-11-23 05:59:58 +00:00
Add SMTP client
This commit is contained in:
parent
19b16c1353
commit
78f1648a9b
@ -3,6 +3,7 @@ using Jellyfin.Plugin.Webhook.Destinations.Discord;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Generic;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Gotify;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Pushover;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Smtp;
|
||||
using MediaBrowser.Model.Plugins;
|
||||
|
||||
namespace Jellyfin.Plugin.Webhook.Configuration
|
||||
@ -22,6 +23,7 @@ namespace Jellyfin.Plugin.Webhook.Configuration
|
||||
GotifyOptions = Array.Empty<GotifyOption>();
|
||||
PushoverOptions = Array.Empty<PushoverOption>();
|
||||
GenericOptions = Array.Empty<GenericOption>();
|
||||
SmtpOptions = Array.Empty<SmtpOption>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -48,5 +50,10 @@ namespace Jellyfin.Plugin.Webhook.Configuration
|
||||
/// Gets or sets the generic options.
|
||||
/// </summary>
|
||||
public GenericOption[] GenericOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the smtp options.
|
||||
/// </summary>
|
||||
public SmtpOption[] SmtpOptions { get; set; }
|
||||
}
|
||||
}
|
@ -29,6 +29,9 @@
|
||||
<button id="btnAddGeneric" is="emby-button" type="button" class="raised button block">
|
||||
<span>Add Generic Destination</span>
|
||||
</button>
|
||||
<button id="btnAddSmtp" is="emby-button" type="button" class="raised button block">
|
||||
<span>Add SMTP Destionation</span>
|
||||
</button>
|
||||
<br/>
|
||||
<div id="configurationWrapper"></div>
|
||||
<br/>
|
||||
@ -196,6 +199,45 @@
|
||||
<input is="emby-input" type="text" data-name="txtValue" label="Value:"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="template-smtp">
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" data-name="txtSenderAddress" label="Sender Address:"/>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" data-name="txtReceiverAddress" label="Receiver Address:"/>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" data-name="txtSmtpServer" label="SMTP Server Address:"/>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" data-name="txtSmtpPort" label="SMTP Port:"/>
|
||||
</div>
|
||||
<label class="checkboxContainer">
|
||||
<input is="emby-checkbox" type="checkbox" data-name="chkUseCredentials"/>
|
||||
<span>Use Credentials</span>
|
||||
</label>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" data-name="txtUsername" label="Username:"/>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" data-name="txtPassword" label="Password:"/>
|
||||
</div>
|
||||
<label class="checkboxContainer">
|
||||
<input is="emby-checkbox" type="checkbox" data-name="chkUseSsl"/>
|
||||
<span>Use SSL</span>
|
||||
</label>
|
||||
<label class="checkboxContainer">
|
||||
<input is="emby-checkbox" type="checkbox" data-name="chkIsHtml"/>
|
||||
<span>Is Html Body</span>
|
||||
</label>
|
||||
<div class="inputContainer">
|
||||
<label>Subject Template:</label>
|
||||
<div>
|
||||
<textarea data-name="txtSubjectTemplate" style="width: 100%; height: 400px"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.checkboxContainer {
|
||||
|
@ -339,12 +339,56 @@
|
||||
element.querySelector("[data-name=field-wrapper]").appendChild(template);
|
||||
}
|
||||
},
|
||||
smtp: {
|
||||
btnAdd: document.querySelector("#btnAddSmtp"),
|
||||
template: document.querySelector("#template-smtp"),
|
||||
addConfig: function (config) {
|
||||
const template = document.createElement("div");
|
||||
template.dataset.type = "smtp";
|
||||
template.appendChild(Webhook.baseConfig.template.cloneNode(true).content);
|
||||
template.appendChild(Webhook.smtp.template.cloneNode(true).content);
|
||||
|
||||
const baseConfig = Webhook.baseConfig.addConfig(template, "SMTP");
|
||||
Webhook.configurationWrapper.appendChild(baseConfig);
|
||||
|
||||
// Load configuration
|
||||
Webhook.smtp.setConfig(config, baseConfig);
|
||||
},
|
||||
setConfig: function (config, element) {
|
||||
Webhook.baseConfig.setConfig(config, element);
|
||||
element.querySelector("[data-name=txtSenderAddress]").value = config.SenderAddress || "";
|
||||
element.querySelector("[data-name=txtReceiverAddress]").value = config.ReceiverAddress || "";
|
||||
element.querySelector("[data-name=txtSmtpServer]").value = config.SmtpServer || "";
|
||||
element.querySelector("[data-name=txtSmtpPort]").value = config.SmtpPort || "";
|
||||
element.querySelector("[data-name=chkUseCredentials]").checked = config.UseCredentials || false;
|
||||
element.querySelector("[data-name=txtUsername]").value = config.Username || "";
|
||||
element.querySelector("[data-name=txtPassword]").value = config.Password || "";
|
||||
element.querySelector("[data-name=chkUseSsl]").checked = config.UseSsl || false;
|
||||
element.querySelector("[data-name=chkIsHtml]").checked = config.IsHtml || false;
|
||||
element.querySelector("[data-name=txtSubjectTemplate]").value = Webhook.atou(config.SubjectTemplate || "");
|
||||
},
|
||||
getConfig: function (element) {
|
||||
const config = Webhook.baseConfig.getConfig(element);
|
||||
config.SenderAddress = element.querySelector("[data-name=txtSenderAddress]").value || "";
|
||||
config.ReceiverAddress = element.querySelector("[data-name=txtReceiverAddress]").value || "";
|
||||
config.SmtpServer = element.querySelector("[data-name=txtSmtpServer]").value || "";
|
||||
config.SmtpPort = element.querySelector("[data-name=txtSmtpPort]").value || "";
|
||||
config.UseCredentials = element.querySelector("[data-name=chkUseCredentials]").checked || false;
|
||||
config.Username = element.querySelector("[data-name=txtUsername]").value || "";
|
||||
config.Password = element.querySelector("[data-name=txtPassword]").value || "";
|
||||
config.UseSsl = element.querySelector("[data-name=chkUseSsl]").checked || false;
|
||||
config.IsHtml = element.querySelector("[data-name=chkIsHtml]").checked || false;
|
||||
config.SubjectTemplate = Webhook.utoa(element.querySelector("[data-name=txtSubjectTemplate]").value || "");
|
||||
return config;
|
||||
}
|
||||
},
|
||||
init: function () {
|
||||
// Add click handlers
|
||||
Webhook.discord.btnAdd.addEventListener("click", Webhook.discord.addConfig);
|
||||
Webhook.gotify.btnAdd.addEventListener("click", Webhook.gotify.addConfig);
|
||||
Webhook.pushover.btnAdd.addEventListener("click", Webhook.pushover.addConfig);
|
||||
Webhook.generic.btnAdd.addEventListener("click", Webhook.generic.addConfig);
|
||||
Webhook.smtp.btnAdd.addEventListener("click", Webhook.smtp.addConfig);
|
||||
document.querySelector("#saveConfig").addEventListener("click", Webhook.saveConfig);
|
||||
|
||||
Webhook.loadConfig();
|
||||
@ -384,6 +428,12 @@
|
||||
config.GenericOptions.push(Webhook.generic.getConfig(genericConfigs[i]));
|
||||
}
|
||||
|
||||
config.SmtpOptions = [];
|
||||
const smtpConfigs = document.querySelectorAll("[data-type=smtp]");
|
||||
for (let i = 0; i < smtpConfigs.length; i++) {
|
||||
config.SmtpOptions.push(Webhook.smtp.getConfig(smtpConfigs[i]));
|
||||
}
|
||||
|
||||
window.ApiClient.updatePluginConfiguration(Webhook.pluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
|
||||
},
|
||||
loadConfig: function () {
|
||||
@ -406,6 +456,10 @@
|
||||
for (let i = 0; i < config.GenericOptions.length; i++) {
|
||||
Webhook.generic.addConfig(config.GenericOptions[i]);
|
||||
}
|
||||
|
||||
for (let i = 0; i < config.SmtpOptions.length; i++) {
|
||||
Webhook.smtp.addConfig(config.SmtpOptions[i]);
|
||||
}
|
||||
});
|
||||
|
||||
Dashboard.hideLoadingMsg()
|
||||
|
53
Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs
Normal file
53
Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MimeKit;
|
||||
|
||||
namespace Jellyfin.Plugin.Webhook.Destinations.Smtp
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class SmtpClient : IWebhookClient<SmtpOption>
|
||||
{
|
||||
private readonly ILogger<SmtpClient> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SmtpClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">Instance of the <see cref="ILogger{SmtpClient}"/> interface.</param>
|
||||
public SmtpClient(ILogger<SmtpClient> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task SendAsync(SmtpOption options, Dictionary<string, object> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = new MimeMessage();
|
||||
message.From.Add(new MailboxAddress(options.SenderAddress, options.SenderAddress));
|
||||
message.To.Add(new MailboxAddress(options.ReceiverAddress, options.ReceiverAddress));
|
||||
|
||||
message.Subject = options.GetSubjectTemplate()(data);
|
||||
message.Body = new TextPart(options.IsHtml ? "html" : "plain")
|
||||
{
|
||||
Text = options.GetCompiledTemplate()(data)
|
||||
};
|
||||
|
||||
using var smtpClient = new MailKit.Net.Smtp.SmtpClient();
|
||||
await smtpClient.ConnectAsync(options.SmtpServer, options.SmtpPort, options.UseSsl);
|
||||
if (options.UseCredentials)
|
||||
{
|
||||
await smtpClient.AuthenticateAsync(options.Username, options.Password);
|
||||
}
|
||||
|
||||
await smtpClient.SendAsync(message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogWarning(e, "Error sending email");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
72
Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpOption.cs
Normal file
72
Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpOption.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using HandlebarsDotNet;
|
||||
using Jellyfin.Plugin.Webhook.Helpers;
|
||||
|
||||
namespace Jellyfin.Plugin.Webhook.Destinations.Smtp
|
||||
{
|
||||
/// <summary>
|
||||
/// Smtp specific option.
|
||||
/// </summary>
|
||||
public class SmtpOption : BaseOption
|
||||
{
|
||||
private HandlebarsTemplate<object, string>? _compiledSubjectTemplate;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sender address.
|
||||
/// </summary>
|
||||
public string SenderAddress { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the receiver address.
|
||||
/// </summary>
|
||||
public string ReceiverAddress { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the smtp server.
|
||||
/// </summary>
|
||||
public string SmtpServer { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the smtp port.
|
||||
/// </summary>
|
||||
public int SmtpPort { get; set; } = 25;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether use credentials.
|
||||
/// </summary>
|
||||
public bool UseCredentials { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the username.
|
||||
/// </summary>
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the password.
|
||||
/// </summary>
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to use ssl.
|
||||
/// </summary>
|
||||
public bool UseSsl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the body is html.
|
||||
/// </summary>
|
||||
public bool IsHtml { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the email subject template.
|
||||
/// </summary>
|
||||
public string SubjectTemplate { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the compiled handlebars subject template.
|
||||
/// </summary>
|
||||
/// <returns>The compiled handlebars subject template.</returns>
|
||||
public HandlebarsTemplate<object, string> GetSubjectTemplate()
|
||||
{
|
||||
return _compiledSubjectTemplate ??= Handlebars.Compile(HandlebarsFunctionHelpers.Base64Decode(SubjectTemplate));
|
||||
}
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MailKit" Version="2.10.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.*" PrivateAssets="All" />
|
||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System.Net.Http.Headers;
|
||||
using Jellyfin.Data.Events;
|
||||
using Jellyfin.Data.Events;
|
||||
using Jellyfin.Data.Events.System;
|
||||
using Jellyfin.Data.Events.Users;
|
||||
using Jellyfin.Plugin.Webhook.Destinations;
|
||||
@ -7,9 +6,9 @@ using Jellyfin.Plugin.Webhook.Destinations.Discord;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Generic;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Gotify;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Pushover;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Smtp;
|
||||
using Jellyfin.Plugin.Webhook.Notifiers;
|
||||
using Jellyfin.Plugin.Webhook.Notifiers.ItemAddedNotifier;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Plugins;
|
||||
using MediaBrowser.Common.Updates;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
@ -36,6 +35,7 @@ namespace Jellyfin.Plugin.Webhook
|
||||
serviceCollection.AddScoped<IWebhookClient<GenericOption>, GenericClient>();
|
||||
serviceCollection.AddScoped<IWebhookClient<GotifyOption>, GotifyClient>();
|
||||
serviceCollection.AddScoped<IWebhookClient<PushoverOption>, PushoverClient>();
|
||||
serviceCollection.AddScoped<IWebhookClient<SmtpOption>, SmtpClient>();
|
||||
|
||||
// Register sender.
|
||||
serviceCollection.AddScoped<IWebhookSender, WebhookSender>();
|
||||
|
@ -8,6 +8,7 @@ using Jellyfin.Plugin.Webhook.Destinations.Discord;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Generic;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Gotify;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Pushover;
|
||||
using Jellyfin.Plugin.Webhook.Destinations.Smtp;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
@ -23,6 +24,7 @@ namespace Jellyfin.Plugin.Webhook
|
||||
private readonly IWebhookClient<GotifyOption> _gotifyClient;
|
||||
private readonly IWebhookClient<PushoverOption> _pushoverClient;
|
||||
private readonly IWebhookClient<GenericOption> _genericClient;
|
||||
private readonly IWebhookClient<SmtpOption> _smtpClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebhookSender"/> class.
|
||||
@ -30,20 +32,23 @@ namespace Jellyfin.Plugin.Webhook
|
||||
/// <param name="logger">Instance of the <see cref="ILogger{WebhookSender}"/> interface.</param>
|
||||
/// <param name="discordClient">Instance of <see cref="IWebhookClient{DiscordOption}"/>.</param>
|
||||
/// <param name="gotifyClient">Instance of <see cref="IWebhookClient{GotifyOption}"/>.</param>
|
||||
/// <param name="pushoverClient">Instance of the <see cref="IWebhookClient{PushoverClient}"/>.</param>
|
||||
/// <param name="genericClient">Instance of the <see cref="IWebhookClient{GenericClient}"/>.</param>
|
||||
/// <param name="pushoverClient">Instance of the <see cref="IWebhookClient{PushoverOption}"/>.</param>
|
||||
/// <param name="genericClient">Instance of the <see cref="IWebhookClient{GenericOption}"/>.</param>
|
||||
/// <param name="smtpClient">Instance of the <see cref="IWebhookClient{SmtpOption}"/>.</param>
|
||||
public WebhookSender(
|
||||
ILogger<WebhookSender> logger,
|
||||
IWebhookClient<DiscordOption> discordClient,
|
||||
IWebhookClient<GotifyOption> gotifyClient,
|
||||
IWebhookClient<PushoverOption> pushoverClient,
|
||||
IWebhookClient<GenericOption> genericClient)
|
||||
IWebhookClient<GenericOption> genericClient,
|
||||
IWebhookClient<SmtpOption> smtpClient)
|
||||
{
|
||||
_logger = logger;
|
||||
_discordClient = discordClient;
|
||||
_gotifyClient = gotifyClient;
|
||||
_pushoverClient = pushoverClient;
|
||||
_genericClient = genericClient;
|
||||
_smtpClient = smtpClient;
|
||||
}
|
||||
|
||||
private static PluginConfiguration Configuration =>
|
||||
@ -72,6 +77,11 @@ namespace Jellyfin.Plugin.Webhook
|
||||
{
|
||||
await SendNotification(_genericClient, option, itemData, itemType);
|
||||
}
|
||||
|
||||
foreach (var option in Configuration.SmtpOptions.Where(o => o.NotificationTypes.Contains(notificationType)))
|
||||
{
|
||||
await SendNotification(_smtpClient, option, itemData, itemType);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool NotifyOnItem<T>(T baseOptions, Type? itemType)
|
||||
|
@ -100,6 +100,7 @@ See [Templates](Jellyfin.Plugin.Webhook/Templates) for sample templates.
|
||||
- Username
|
||||
- Gotify
|
||||
- Priority
|
||||
- Pushbullet
|
||||
- Pushover
|
||||
- Token
|
||||
- UserToken
|
||||
@ -109,6 +110,7 @@ See [Templates](Jellyfin.Plugin.Webhook/Templates) for sample templates.
|
||||
- MessageUrlTitle
|
||||
- MessagePriority
|
||||
- NotificationSound
|
||||
- SMTP
|
||||
|
||||
Future events can be created
|
||||
from https://github.com/jellyfin/jellyfin/blob/master/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs
|
@ -12,5 +12,8 @@ category: "Notifications"
|
||||
artifacts:
|
||||
- "Jellyfin.Plugin.Webhook.dll"
|
||||
- "Handlebars.dll"
|
||||
- "MailKit.dll"
|
||||
- "MimeKit.dll"
|
||||
- "BouncyCastle.Crypto.dll"
|
||||
changelog: >
|
||||
Add more notification types
|
||||
Add SMTP and Pushullet clients
|
||||
|
Loading…
Reference in New Issue
Block a user