diff --git a/Tranga/LibraryConnectors/Kavita.cs b/Tranga/LibraryConnectors/Kavita.cs index a9d2fa9..62150a0 100644 --- a/Tranga/LibraryConnectors/Kavita.cs +++ b/Tranga/LibraryConnectors/Kavita.cs @@ -61,7 +61,7 @@ public class Kavita : LibraryConnector return ""; } - public override void UpdateLibrary() + protected override void UpdateLibraryInternal() { Log("Updating libraries."); foreach (KavitaLibrary lib in GetLibraries()) diff --git a/Tranga/LibraryConnectors/Komga.cs b/Tranga/LibraryConnectors/Komga.cs index 557d934..2d6b2a1 100644 --- a/Tranga/LibraryConnectors/Komga.cs +++ b/Tranga/LibraryConnectors/Komga.cs @@ -25,7 +25,7 @@ public class Komga : LibraryConnector return $"Komga {baseUrl}"; } - public override void UpdateLibrary() + protected override void UpdateLibraryInternal() { Log("Updating libraries."); foreach (KomgaLibrary lib in GetLibraries()) diff --git a/Tranga/LibraryConnectors/LibraryConnector.cs b/Tranga/LibraryConnectors/LibraryConnector.cs index 80dd5b2..99320b0 100644 --- a/Tranga/LibraryConnectors/LibraryConnector.cs +++ b/Tranga/LibraryConnectors/LibraryConnector.cs @@ -17,6 +17,9 @@ public abstract class LibraryConnector : GlobalBase public string baseUrl { get; } // ReSharper disable once MemberCanBeProtected.Global public string auth { get; } //Base64 encoded, if you use your password everywhere, you have problems + private DateTime? _updateLibraryRequested = null; + private readonly Thread? _libraryBufferThread = null; + private const int NoChangeTimeout = 2, BiggestInterval = 20; protected LibraryConnector(GlobalBase clone, string baseUrl, string auth, LibraryType libraryType) : base(clone) { @@ -28,8 +31,47 @@ public abstract class LibraryConnector : GlobalBase this.baseUrl = baseUrlRex.Match(baseUrl).Value; this.auth = auth; this.libraryType = libraryType; + + if (TrangaSettings.bufferLibraryUpdates) + { + _libraryBufferThread = new(CheckLibraryBuffer); + _libraryBufferThread.Start(); + } } - public abstract void UpdateLibrary(); + + private void CheckLibraryBuffer() + { + while (true) + { + if (_updateLibraryRequested is not null && DateTime.Now.Subtract((DateTime)_updateLibraryRequested) > TimeSpan.FromMinutes(NoChangeTimeout)) //If no updates have been requested for NoChangeTimeout minutes, update library + { + UpdateLibraryInternal(); + _updateLibraryRequested = null; + } + Thread.Sleep(100); + } + } + + public void UpdateLibrary() + { + _updateLibraryRequested ??= DateTime.Now; + if (!TrangaSettings.bufferLibraryUpdates) + { + UpdateLibraryInternal(); + return; + }else if (_updateLibraryRequested is not null && + DateTime.Now.Subtract((DateTime)_updateLibraryRequested) > TimeSpan.FromMinutes(BiggestInterval)) //If the last update has been more than BiggestInterval minutes ago, update library + { + UpdateLibraryInternal(); + _updateLibraryRequested = null; + } + else if(_updateLibraryRequested is not null) + { + Log($"Buffering Library Updates (Updates in latest {((DateTime)_updateLibraryRequested).Add(TimeSpan.FromMinutes(BiggestInterval)).Subtract(DateTime.Now)} or {((DateTime)_updateLibraryRequested).Add(TimeSpan.FromMinutes(NoChangeTimeout)).Subtract(DateTime.Now)})"); + } + } + + protected abstract void UpdateLibraryInternal(); internal abstract bool Test(); protected static class NetClient diff --git a/Tranga/TrangaSettings.cs b/Tranga/TrangaSettings.cs index b945fe5..3615d63 100644 --- a/Tranga/TrangaSettings.cs +++ b/Tranga/TrangaSettings.cs @@ -15,6 +15,7 @@ public static class TrangaSettings public static string workingDirectory { get; private set; } = Path.Join(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "/usr/share" : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "tranga-api"); public static int apiPortNumber { get; private set; } = 6531; public static string userAgent { get; private set; } = DefaultUserAgent; + public static bool bufferLibraryUpdates { get; private set; } = false; [JsonIgnore] public static string settingsFilePath => Path.Join(workingDirectory, "settings.json"); [JsonIgnore] public static string libraryConnectorsFilePath => Path.Join(workingDirectory, "libraryConnectors.json"); [JsonIgnore] public static string notificationConnectorsFilePath => Path.Join(workingDirectory, "notificationConnectors.json"); @@ -46,15 +47,16 @@ public static class TrangaSettings ExportSettings(); } - public static void CreateOrUpdate(string? downloadDirectory = null, string? pWorkingDirectory = null, int? pApiPortNumber = null, string? pUserAgent = null, bool? pAprilFoolsMode = null) + public static void CreateOrUpdate(string? downloadDirectory = null, string? pWorkingDirectory = null, int? pApiPortNumber = null, string? pUserAgent = null, bool? pAprilFoolsMode = null, bool? pBufferLibraryUpdates = null) { if(pWorkingDirectory is null && File.Exists(settingsFilePath)) LoadFromWorkingDirectory(workingDirectory); - TrangaSettings.downloadLocation = downloadDirectory ?? TrangaSettings.downloadLocation; - TrangaSettings.workingDirectory = pWorkingDirectory ?? TrangaSettings.workingDirectory; - TrangaSettings.apiPortNumber = pApiPortNumber ?? TrangaSettings.apiPortNumber; - TrangaSettings.userAgent = pUserAgent ?? TrangaSettings.userAgent; - TrangaSettings.aprilFoolsMode = pAprilFoolsMode ?? TrangaSettings.aprilFoolsMode; + downloadLocation = downloadDirectory ?? downloadLocation; + workingDirectory = pWorkingDirectory ?? workingDirectory; + apiPortNumber = pApiPortNumber ?? apiPortNumber; + userAgent = pUserAgent ?? userAgent; + aprilFoolsMode = pAprilFoolsMode ?? aprilFoolsMode; + bufferLibraryUpdates = pBufferLibraryUpdates ?? bufferLibraryUpdates; Directory.CreateDirectory(downloadLocation); Directory.CreateDirectory(workingDirectory); ExportSettings(); @@ -90,7 +92,7 @@ public static class TrangaSettings public static void UpdateAprilFoolsMode(bool enabled) { - TrangaSettings.aprilFoolsMode = enabled; + aprilFoolsMode = enabled; ExportSettings(); } @@ -102,10 +104,10 @@ public static class TrangaSettings else Directory.CreateDirectory(newPath); - if (moveFiles && Directory.Exists(TrangaSettings.downloadLocation)) - Directory.Move(TrangaSettings.downloadLocation, newPath); + if (moveFiles && Directory.Exists(downloadLocation)) + Directory.Move(downloadLocation, newPath); - TrangaSettings.downloadLocation = newPath; + downloadLocation = newPath; ExportSettings(); } @@ -116,26 +118,26 @@ public static class TrangaSettings GroupRead | GroupWrite | None | OtherRead | OtherWrite | UserRead | UserWrite); else Directory.CreateDirectory(newPath); - Directory.Move(TrangaSettings.workingDirectory, newPath); - TrangaSettings.workingDirectory = newPath; + Directory.Move(workingDirectory, newPath); + workingDirectory = newPath; ExportSettings(); } public static void UpdateUserAgent(string? customUserAgent) { - TrangaSettings.userAgent = customUserAgent ?? DefaultUserAgent; + userAgent = customUserAgent ?? DefaultUserAgent; ExportSettings(); } public static void UpdateRateLimit(RequestType requestType, int newLimit) { - TrangaSettings.requestLimits[requestType] = newLimit; + requestLimits[requestType] = newLimit; ExportSettings(); } public static void ResetRateLimits() { - TrangaSettings.requestLimits = DefaultRequestLimits; + requestLimits = DefaultRequestLimits; ExportSettings(); } @@ -154,13 +156,14 @@ public static class TrangaSettings public static JObject AsJObject() { JObject jobj = new JObject(); - jobj.Add("downloadLocation", JToken.FromObject(TrangaSettings.downloadLocation)); - jobj.Add("workingDirectory", JToken.FromObject(TrangaSettings.workingDirectory)); - jobj.Add("apiPortNumber", JToken.FromObject(TrangaSettings.apiPortNumber)); - jobj.Add("userAgent", JToken.FromObject(TrangaSettings.userAgent)); - jobj.Add("aprilFoolsMode", JToken.FromObject(TrangaSettings.aprilFoolsMode)); - jobj.Add("version", JToken.FromObject(TrangaSettings.version)); - jobj.Add("requestLimits", JToken.FromObject(TrangaSettings.requestLimits)); + jobj.Add("downloadLocation", JToken.FromObject(downloadLocation)); + jobj.Add("workingDirectory", JToken.FromObject(workingDirectory)); + jobj.Add("apiPortNumber", JToken.FromObject(apiPortNumber)); + jobj.Add("userAgent", JToken.FromObject(userAgent)); + jobj.Add("aprilFoolsMode", JToken.FromObject(aprilFoolsMode)); + jobj.Add("version", JToken.FromObject(version)); + jobj.Add("requestLimits", JToken.FromObject(requestLimits)); + jobj.Add("bufferLibraryUpdates", JToken.FromObject(bufferLibraryUpdates)); return jobj; } @@ -170,16 +173,18 @@ public static class TrangaSettings { JObject jobj = JObject.Parse(serialized); if (jobj.TryGetValue("downloadLocation", out JToken? dl)) - TrangaSettings.downloadLocation = dl.Value()!; + downloadLocation = dl.Value()!; if (jobj.TryGetValue("workingDirectory", out JToken? wd)) - TrangaSettings.workingDirectory = wd.Value()!; + workingDirectory = wd.Value()!; if (jobj.TryGetValue("apiPortNumber", out JToken? apn)) - TrangaSettings.apiPortNumber = apn.Value(); + apiPortNumber = apn.Value(); if (jobj.TryGetValue("userAgent", out JToken? ua)) - TrangaSettings.userAgent = ua.Value()!; + userAgent = ua.Value()!; if (jobj.TryGetValue("aprilFoolsMode", out JToken? afm)) - TrangaSettings.aprilFoolsMode = afm.Value()!; + aprilFoolsMode = afm.Value()!; if (jobj.TryGetValue("requestLimits", out JToken? rl)) - TrangaSettings.requestLimits = rl.ToObject>()!; + requestLimits = rl.ToObject>()!; + if (jobj.TryGetValue("bufferLibraryUpdates", out JToken? blu)) + bufferLibraryUpdates = blu.Value()!; } } \ No newline at end of file