diff --git a/SynoAI/Controllers/ImageController.cs b/SynoAI/Controllers/ImageController.cs
index cdbcdae..c40e09b 100644
--- a/SynoAI/Controllers/ImageController.cs
+++ b/SynoAI/Controllers/ImageController.cs
@@ -6,9 +6,7 @@ namespace SynoAI.Controllers
public class ImageController : Controller
{
///
- /// Return snapshot image as JPEG, either in original size or a scaled down version, if asked.
- //// In order to use System.Drawing.Common
- //// In Terminal, issue: dotnet add SynoAI package System.Drawing.Common
+ /// Returns the file for the specified camera.
///
[Route("Image/{cameraName}/{filename}")]
public ActionResult Get(string cameraName, string filename)
diff --git a/SynoAI/Notifiers/NotifierFactory.cs b/SynoAI/Notifiers/NotifierFactory.cs
index 1a24fe8..3621388 100644
--- a/SynoAI/Notifiers/NotifierFactory.cs
+++ b/SynoAI/Notifiers/NotifierFactory.cs
@@ -3,6 +3,7 @@
using SynoAI.Notifiers.Email;
using SynoAI.Notifiers.Pushbullet;
using SynoAI.Notifiers.Pushover;
+using SynoAI.Notifiers.SynologyChat;
using SynoAI.Notifiers.Telegram;
using SynoAI.Notifiers.Webhook;
using System;
@@ -31,6 +32,9 @@ public static INotifier Create(NotifierType type, ILogger logger, IConfiguration
case NotifierType.Pushover:
factory = new PushoverFactory();
break;
+ case NotifierType.SynologyChat:
+ factory = new SynologyChatFactory();
+ break;
case NotifierType.Telegram:
factory = new TelegramFactory();
break;
diff --git a/SynoAI/Notifiers/NotifierType.cs b/SynoAI/Notifiers/NotifierType.cs
index b264da0..639367d 100644
--- a/SynoAI/Notifiers/NotifierType.cs
+++ b/SynoAI/Notifiers/NotifierType.cs
@@ -19,12 +19,16 @@ public enum NotifierType
///
Pushover,
///
+ /// Sends a notification message and image using the SynologyChat API.
+ ///
+ SynologyChat,
+ ///
/// Sends a notification to Telegram with the image attached.
///
Telegram,
///
/// Calls a webhook with the image attached.
///
- Webhook
+ Webhook,
}
}
diff --git a/SynoAI/Notifiers/SynologyChat/SynologyChat.cs b/SynoAI/Notifiers/SynologyChat/SynologyChat.cs
new file mode 100644
index 0000000..fd58f52
--- /dev/null
+++ b/SynoAI/Notifiers/SynologyChat/SynologyChat.cs
@@ -0,0 +1,83 @@
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using SynoAI.Models;
+using SynoAI.Services;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Net.Http.Json;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SynoAI.Notifiers.SynologyChat
+{
+ ///
+ /// Calls a third party API.
+ ///
+ public class SynologyChat : NotifierBase
+ {
+ ///
+ /// The URL to send the request to including the token.
+ ///
+ public string Url { get; set; }
+
+ ///
+ /// Sends a notification to the Webhook.
+ ///
+ /// The camera that triggered the notification.
+ /// The notification data to process.
+ /// A logger.
+ public override async Task SendAsync(Camera camera, Notification notification, ILogger logger)
+ {
+ logger.LogInformation($"{camera.Name}: SynologyChat: Processing");
+ using (HttpClient client = new())
+ {
+ IEnumerable foundTypes = notification.FoundTypes;
+ string message = GetMessage(camera, foundTypes);
+
+ var request = new
+ {
+ text = message,
+ file_url = new Uri(new Uri(Config.Url), new Uri($"Image/{camera.Name}/{notification.ProcessedImage.FileName}", UriKind.Relative))
+ };
+
+ string requestJson = JsonConvert.SerializeObject(request);
+ Dictionary payload = new()
+ {
+ { "payload", requestJson },
+ };
+
+ using (FormUrlEncodedContent content = new(payload))
+ {
+ content.Headers.Clear();
+ content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
+
+ logger.LogInformation($"{camera.Name}: SynologyChat: POSTing message.");
+
+ HttpResponseMessage response = await client.PostAsync(Url, content);
+ if (response.IsSuccessStatusCode)
+ {
+ // Check that it's actually successful, because Synology like to make things awkward
+ string responseString = await response.Content.ReadAsStringAsync();
+ SynologyChatResponse actualResponse = JsonConvert.DeserializeObject(responseString);
+ if (actualResponse.Success)
+ {
+ logger.LogInformation($"{camera.Name}: SynologyChat: Success.");
+ }
+ else
+ {
+ logger.LogInformation($"{camera.Name}: SynologyChat: Failed with error '{actualResponse.Error.Code}': {actualResponse.Error.Errors}.");
+ }
+ }
+ else
+ {
+ logger.LogWarning($"{camera.Name}: SynologyChat: The end point responded with HTTP status code '{response.StatusCode}'.");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/SynoAI/Notifiers/SynologyChat/SynologyChatErrorReasonResponse.cs b/SynoAI/Notifiers/SynologyChat/SynologyChatErrorReasonResponse.cs
new file mode 100644
index 0000000..37c815c
--- /dev/null
+++ b/SynoAI/Notifiers/SynologyChat/SynologyChatErrorReasonResponse.cs
@@ -0,0 +1,17 @@
+using Newtonsoft.Json;
+
+namespace SynoAI.Notifiers.SynologyChat
+{
+ public class SynologyChatErrorReasonResponse
+ {
+ [JsonProperty("name")]
+ public string Name { get; set; }
+ [JsonProperty("reason")]
+ public string Reason { get; set; }
+
+ public override string ToString()
+ {
+ return $"{Name} ({Reason})";
+ }
+ }
+}
diff --git a/SynoAI/Notifiers/SynologyChat/SynologyChatErrorResponse.cs b/SynoAI/Notifiers/SynologyChat/SynologyChatErrorResponse.cs
new file mode 100644
index 0000000..46afb1e
--- /dev/null
+++ b/SynoAI/Notifiers/SynologyChat/SynologyChatErrorResponse.cs
@@ -0,0 +1,13 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace SynoAI.Notifiers.SynologyChat
+{
+ public class SynologyChatErrorResponse
+ {
+ [JsonProperty("code")]
+ public string Code { get; set; }
+ [JsonProperty("errors")]
+ public SynologyChatErrorReasonResponse Errors { get; set; }
+ }
+}
diff --git a/SynoAI/Notifiers/SynologyChat/SynologyChatFactory.cs b/SynoAI/Notifiers/SynologyChat/SynologyChatFactory.cs
new file mode 100644
index 0000000..65ca11f
--- /dev/null
+++ b/SynoAI/Notifiers/SynologyChat/SynologyChatFactory.cs
@@ -0,0 +1,25 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace SynoAI.Notifiers.SynologyChat
+{
+ public class SynologyChatFactory : NotifierFactory
+ {
+ public override INotifier Create(ILogger logger, IConfigurationSection section)
+ {
+ using (logger.BeginScope(nameof(SynologyChatFactory)))
+ {
+ logger.LogInformation($"Processing {nameof(SynologyChat)} Config");
+
+ string url = section.GetValue("Url");
+
+ SynologyChat webhook = new SynologyChat()
+ {
+ Url = url
+ };
+
+ return webhook;
+ }
+ }
+ }
+}
diff --git a/SynoAI/Notifiers/SynologyChat/SynologyChatResponse.cs b/SynoAI/Notifiers/SynologyChat/SynologyChatResponse.cs
new file mode 100644
index 0000000..db6e00d
--- /dev/null
+++ b/SynoAI/Notifiers/SynologyChat/SynologyChatResponse.cs
@@ -0,0 +1,12 @@
+using Newtonsoft.Json;
+
+namespace SynoAI.Notifiers.SynologyChat
+{
+ public class SynologyChatResponse
+ {
+ [JsonProperty("success")]
+ public bool Success { get; set; }
+ [JsonProperty("error")]
+ public SynologyChatErrorResponse Error { get; set; }
+ }
+}