diff --git a/Tranga-API/Program.cs b/Tranga-API/Program.cs index 78b4253..80d1307 100644 --- a/Tranga-API/Program.cs +++ b/Tranga-API/Program.cs @@ -18,7 +18,7 @@ TrangaSettings settings; if (File.Exists(settingsFilePath)) settings = TrangaSettings.LoadSettings(settingsFilePath, logger); else - settings = new TrangaSettings(downloadFolderPath, applicationFolderPath, new HashSet()); + settings = new TrangaSettings(downloadFolderPath, applicationFolderPath, new HashSet(), new HashSet()); Directory.CreateDirectory(settings.workingDirectory); Directory.CreateDirectory(settings.downloadLocation); @@ -243,7 +243,19 @@ app.MapDelete("/Queue/Dequeue", (string taskType, string? connectorName, string? app.MapGet("/Settings/Get", () => taskManager.settings); app.MapPost("/Settings/Update", - (string? downloadLocation, string? komgaUrl, string? komgaAuth, string? kavitaUrl, string? kavitaUsername, string? kavitaPassword) => - taskManager.UpdateSettings(downloadLocation, komgaUrl, komgaAuth, kavitaUrl, kavitaUsername, kavitaPassword)); + (string? downloadLocation, string? komgaUrl, string? komgaAuth, string? kavitaUrl, string? kavitaUsername, + string? kavitaPassword, string? gotifyUrl, string? gotifyAppToken) => + { + if (downloadLocation is not null && downloadLocation.Length > 0) + taskManager.settings.UpdateSettings(TrangaSettings.UpdateField.DownloadLocation, logger, downloadLocation); + if (komgaUrl is not null && komgaAuth is not null && komgaUrl.Length > 5 && komgaAuth.Length > 0) + taskManager.settings.UpdateSettings(TrangaSettings.UpdateField.Komga, logger, komgaUrl, komgaAuth); + if (kavitaUrl is not null && kavitaPassword is not null && kavitaUsername is not null && kavitaUrl.Length > 5 && + kavitaUsername.Length > 0 && kavitaPassword.Length > 0) + taskManager.settings.UpdateSettings(TrangaSettings.UpdateField.Kavita, logger, kavitaUrl, kavitaUsername, + kavitaPassword); + if (gotifyUrl is not null && gotifyAppToken is not null && gotifyUrl.Length > 5 && gotifyAppToken.Length > 0) + taskManager.settings.UpdateSettings(TrangaSettings.UpdateField.Gotify, logger, gotifyUrl, gotifyAppToken); + }); app.Run(); \ No newline at end of file diff --git a/Tranga-CLI/Tranga_Cli.cs b/Tranga-CLI/Tranga_Cli.cs index f4da68d..e0267a1 100644 --- a/Tranga-CLI/Tranga_Cli.cs +++ b/Tranga-CLI/Tranga_Cli.cs @@ -2,6 +2,7 @@ using Logging; using Tranga; using Tranga.LibraryManagers; +using Tranga.NotificationManagers; using Tranga.TrangaTasks; namespace Tranga_CLI; @@ -30,7 +31,7 @@ public static class Tranga_Cli Logger logger = new(new[] { Logger.LoggerType.FileLogger }, null, Console.Out.Encoding, logFilePath); logger.WriteLine("Tranga_CLI", "Loading Taskmanager."); - TrangaSettings settings = File.Exists(settingsFilePath) ? TrangaSettings.LoadSettings(settingsFilePath, logger) : new TrangaSettings(Directory.GetCurrentDirectory(), applicationFolderPath, new HashSet()); + TrangaSettings settings = File.Exists(settingsFilePath) ? TrangaSettings.LoadSettings(settingsFilePath, logger) : new TrangaSettings(Directory.GetCurrentDirectory(), applicationFolderPath, new HashSet(), new HashSet()); logger.WriteLine("Tranga_CLI", "User Input"); @@ -39,7 +40,7 @@ public static class Tranga_Cli while(tmpPath is null) tmpPath = Console.ReadLine(); if (tmpPath.Length > 0) - settings.downloadLocation = tmpPath; + settings.UpdateSettings(TrangaSettings.UpdateField.DownloadLocation, logger, tmpPath); Console.WriteLine($"Komga BaseURL [{settings.libraryManagers.FirstOrDefault(lm => lm.GetType() == typeof(Komga))?.baseUrl}]:"); string? tmpUrlKomga = Console.ReadLine(); @@ -72,8 +73,7 @@ public static class Tranga_Cli } } while (key != ConsoleKey.Enter); - settings.libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Komga)); - settings.libraryManagers.Add(new Komga(tmpUrlKomga, tmpKomgaUser, tmpKomgaPass, logger)); + settings.UpdateSettings(TrangaSettings.UpdateField.Komga, logger, tmpUrlKomga, tmpKomgaUser, tmpKomgaPass); } Console.WriteLine($"Kavita BaseURL [{settings.libraryManagers.FirstOrDefault(lm => lm.GetType() == typeof(Kavita))?.baseUrl}]:"); @@ -107,11 +107,26 @@ public static class Tranga_Cli } } while (key != ConsoleKey.Enter); - settings.libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Kavita)); - settings.libraryManagers.Add(new Kavita(tmpUrlKavita, tmpKavitaUser, tmpKavitaPass, logger)); + settings.UpdateSettings(TrangaSettings.UpdateField.Kavita, logger, tmpUrlKavita, tmpKavitaUser, tmpKavitaPass); + } + + Console.WriteLine($"Gotify BaseURL [{((Gotify?)settings.notificationManagers.FirstOrDefault(lm => lm.GetType() == typeof(Gotify)))?.endpoint}]:"); + string? tmpGotifyUrl = Console.ReadLine(); + while (tmpGotifyUrl is null) + tmpGotifyUrl = Console.ReadLine(); + if (tmpGotifyUrl.Length > 0) + { + Console.WriteLine("AppToken:"); + string? tmpGotifyAppToken = Console.ReadLine(); + while (tmpGotifyAppToken is null || tmpGotifyAppToken.Length < 1) + tmpGotifyAppToken = Console.ReadLine(); + + settings.UpdateSettings(TrangaSettings.UpdateField.Gotify, logger, tmpGotifyUrl, tmpGotifyAppToken); } logger.WriteLine("Tranga_CLI", "Loaded."); + foreach(NotificationManager nm in settings.notificationManagers) + nm.SendNotification("Tranga", "Loaded."); TaskMode(settings, logger); } diff --git a/Tranga.sln.DotSettings b/Tranga.sln.DotSettings index 4f84134..37bbfaf 100644 --- a/Tranga.sln.DotSettings +++ b/Tranga.sln.DotSettings @@ -1,4 +1,5 @@  + True True True True diff --git a/Tranga/NotificationManager.cs b/Tranga/NotificationManager.cs new file mode 100644 index 0000000..5030288 --- /dev/null +++ b/Tranga/NotificationManager.cs @@ -0,0 +1,49 @@ +using Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Tranga.NotificationManagers; + +namespace Tranga; + +public abstract class NotificationManager +{ + protected Logger? logger; + public NotificationManagerType notificationManagerType { get; } + + protected NotificationManager(NotificationManagerType notificationManagerType, Logger? logger = null) + { + this.notificationManagerType = notificationManagerType; + this.logger = logger; + } + + public enum NotificationManagerType : byte { Gotify = 0 } + + public abstract void SendNotification(string title, string notificationText); + + public class NotificationManagerJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return (objectType == typeof(NotificationManager)); + } + + public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + JObject jo = JObject.Load(reader); + if (jo["notificationManagerType"]!.Value() == (byte)NotificationManagerType.Gotify) + return jo.ToObject(serializer)!; + + throw new Exception(); + } + + public override bool CanWrite => false; + + /// + /// Don't call this + /// + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + throw new Exception("Dont call this"); + } + } +} \ No newline at end of file diff --git a/Tranga/NotificationManagers/Gotify.cs b/Tranga/NotificationManagers/Gotify.cs new file mode 100644 index 0000000..ef14cdd --- /dev/null +++ b/Tranga/NotificationManagers/Gotify.cs @@ -0,0 +1,49 @@ +using System.Text; +using Logging; +using Newtonsoft.Json; + +namespace Tranga.NotificationManagers; + +public class Gotify : NotificationManager +{ + public string endpoint { get; } + public string appToken { get; } + private readonly HttpClient _client = new(); + + public Gotify(string endpoint, string appToken, Logger? logger = null) : base(NotificationManagerType.Gotify, logger) + { + this.endpoint = endpoint; + this.appToken = appToken; + } + + public override void SendNotification(string title, string notificationText) + { + logger?.WriteLine(this.GetType().ToString(), $"Sending notification: {title} - {notificationText}"); + MessageData message = new(title, notificationText); + HttpRequestMessage request = new(HttpMethod.Post, $"{endpoint}/message"); + request.Headers.Add("X-Gotify-Key", this.appToken); + request.Content = new StringContent(JsonConvert.SerializeObject(message, Formatting.None), Encoding.UTF8, "application/json"); + HttpResponseMessage response = _client.Send(request); + if (!response.IsSuccessStatusCode) + { + StreamReader sr = new (response.Content.ReadAsStream()); + logger?.WriteLine(this.GetType().ToString(), $"{response.StatusCode}: {sr.ReadToEnd()}"); + } + } + + private class MessageData + { + public string message { get; } + public long priority { get; } + public string title { get; } + public Dictionary extras { get; } + + public MessageData(string title, string message) + { + this.title = title; + this.message = message; + this.extras = new(); + this.priority = 2; + } + } +} \ No newline at end of file diff --git a/Tranga/TaskManager.cs b/Tranga/TaskManager.cs index 65f7b2c..657ddf5 100644 --- a/Tranga/TaskManager.cs +++ b/Tranga/TaskManager.cs @@ -1,7 +1,6 @@ using Logging; using Newtonsoft.Json; using Tranga.Connectors; -using Tranga.LibraryManagers; using Tranga.TrangaTasks; namespace Tranga; @@ -25,8 +24,9 @@ public class TaskManager /// Path to the working directory /// Path to the cover-image cache /// + /// /// - public TaskManager(string downloadFolderPath, string workingDirectory, string imageCachePath, HashSet libraryManagers, Logger? logger = null) : this(new TrangaSettings(downloadFolderPath, workingDirectory, libraryManagers), logger) + public TaskManager(string downloadFolderPath, string workingDirectory, string imageCachePath, HashSet libraryManagers, HashSet notificationManagers, Logger? logger = null) : this(new TrangaSettings(downloadFolderPath, workingDirectory, libraryManagers, notificationManagers), logger) { } @@ -47,23 +47,6 @@ public class TaskManager Thread taskChecker = new(TaskCheckerThread); taskChecker.Start(); } - - public void UpdateSettings(string? downloadLocation, string? komgaUrl, string? komgaAuth, string? kavitaUrl, string? kavitaUsername, string? kavitaPassword) - { - if (komgaUrl is not null && komgaAuth is not null && komgaUrl.Length > 0 && komgaAuth.Length > 0) - { - settings.libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Komga)); - settings.libraryManagers.Add(new Komga(komgaUrl, komgaAuth, logger)); - } - if (kavitaUrl is not null && kavitaUsername is not null && kavitaPassword is not null && kavitaUrl.Length > 0 && kavitaUsername.Length > 0 && kavitaPassword.Length > 0) - { - settings.libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Kavita)); - settings.libraryManagers.Add(new Kavita(kavitaUrl, kavitaUsername, kavitaPassword, logger)); - } - if (downloadLocation is not null && downloadLocation.Length > 0) - settings.downloadLocation = downloadLocation; - ExportDataAndSettings(); - } /// /// Runs continuously until shutdown. diff --git a/Tranga/TrangaSettings.cs b/Tranga/TrangaSettings.cs index f7a0665..4295d2d 100644 --- a/Tranga/TrangaSettings.cs +++ b/Tranga/TrangaSettings.cs @@ -1,6 +1,7 @@ using Logging; using Newtonsoft.Json; using Tranga.LibraryManagers; +using Tranga.NotificationManagers; namespace Tranga; @@ -8,32 +9,69 @@ public class TrangaSettings { public string downloadLocation { get; set; } public string workingDirectory { get; set; } - [JsonIgnore]public string settingsFilePath => Path.Join(workingDirectory, "settings.json"); - [JsonIgnore]public string tasksFilePath => Path.Join(workingDirectory, "tasks.json"); - [JsonIgnore]public string knownPublicationsPath => Path.Join(workingDirectory, "knownPublications.json"); + [JsonIgnore] public string settingsFilePath => Path.Join(workingDirectory, "settings.json"); + [JsonIgnore] public string tasksFilePath => Path.Join(workingDirectory, "tasks.json"); + [JsonIgnore] public string knownPublicationsPath => Path.Join(workingDirectory, "knownPublications.json"); [JsonIgnore] public string coverImageCache => Path.Join(workingDirectory, "imageCache"); public HashSet libraryManagers { get; } + public HashSet notificationManagers { get; } - public TrangaSettings(string downloadLocation, string workingDirectory, HashSet libraryManagers) + public TrangaSettings(string downloadLocation, string workingDirectory, HashSet libraryManagers, + HashSet notificationManagers) { if (downloadLocation.Length < 1 || workingDirectory.Length < 1) throw new ArgumentException("Download-location and working-directory paths can not be empty!"); this.workingDirectory = workingDirectory; this.downloadLocation = downloadLocation; this.libraryManagers = libraryManagers; + this.notificationManagers = notificationManagers; } public static TrangaSettings LoadSettings(string importFilePath, Logger? logger) { if (!File.Exists(importFilePath)) - return new TrangaSettings(Path.Join(Directory.GetCurrentDirectory(), "Downloads"), Directory.GetCurrentDirectory(), new HashSet()); + return new TrangaSettings(Path.Join(Directory.GetCurrentDirectory(), "Downloads"), + Directory.GetCurrentDirectory(), new HashSet(), new HashSet()); string toRead = File.ReadAllText(importFilePath); - TrangaSettings settings = JsonConvert.DeserializeObject(toRead, new JsonSerializerSettings() { Converters = { new LibraryManager.LibraryManagerJsonConverter()} })!; - if(logger is not null) - foreach(LibraryManager lm in settings.libraryManagers) + TrangaSettings settings = JsonConvert.DeserializeObject(toRead, + new JsonSerializerSettings { Converters = { new NotificationManager.NotificationManagerJsonConverter(), new LibraryManager.LibraryManagerJsonConverter() } })!; + if (logger is not null) + foreach (LibraryManager lm in settings.libraryManagers) lm.AddLogger(logger); return settings; } + + public void UpdateSettings(UpdateField field, Logger? logger = null, params string[] values) + { + switch (field) + { + case UpdateField.DownloadLocation: + if (values.Length != 1) + return; + this.downloadLocation = values[0]; + break; + case UpdateField.Komga: + if (values.Length != 2) + return; + libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Komga)); + libraryManagers.Add(new Komga(values[0], values[1], logger)); + break; + case UpdateField.Kavita: + if (values.Length != 3) + return; + libraryManagers.RemoveWhere(lm => lm.GetType() == typeof(Kavita)); + libraryManagers.Add(new Kavita(values[0], values[1], values[2], logger)); + break; + case UpdateField.Gotify: + if (values.Length != 2) + return; + notificationManagers.RemoveWhere(nm => nm.GetType() == typeof(Gotify)); + notificationManagers.Add(new Gotify(values[0], values[1], logger)); + break; + } + } + + public enum UpdateField { DownloadLocation, Komga, Kavita, Gotify} } \ No newline at end of file diff --git a/Tranga/TrangaTasks/DownloadNewChaptersTask.cs b/Tranga/TrangaTasks/DownloadNewChaptersTask.cs index df46409..260fb01 100644 --- a/Tranga/TrangaTasks/DownloadNewChaptersTask.cs +++ b/Tranga/TrangaTasks/DownloadNewChaptersTask.cs @@ -36,6 +36,9 @@ public class DownloadNewChaptersTask : TrangaTask taskManager.AddTask(newTask); this.childTasks.Add(newTask); } + if(newChapters.Count > 0) + foreach(NotificationManager nm in taskManager.settings.notificationManagers) + nm.SendNotification(pub.sortName, $"Downloading {newChapters.Count} new Chapters."); } public override string ToString()