From e8832774009846a1e7ca5e5f30d4a353cf3f0daa Mon Sep 17 00:00:00 2001 From: glax Date: Tue, 20 Jun 2023 14:57:44 +0200 Subject: [PATCH] Renamed DownloadNewChaptersTask to MonitorPublicationTask Added TrangaTask.Clone() method Rewrote TrangaTask.progress for the billionth+1 time. Removed Increment and DecrementProgress methods Removed TrangaTask.ReplaceFailedChildTask method Changed return type of TrangaTask.ExecuteTask to bool, signifying success. Added Failed Execution state to TrangaTask Replaced taskManager failed-task logic Removed TaskManager bulky AddTask and DeleteTask methods Removed TaskManager bulky Constructor --- Tranga-API/Program.cs | 20 +- Tranga-CLI/Tranga_Cli.cs | 12 +- Tranga/TaskManager.cs | 200 +++++------------- Tranga/TrangaTask.cs | 74 +++---- Tranga/TrangaTasks/DownloadChapterTask.cs | 29 ++- Tranga/TrangaTasks/DownloadNewChaptersTask.cs | 45 ---- Tranga/TrangaTasks/MonitorPublicationTask.cs | 59 ++++++ Tranga/TrangaTasks/UpdateLibrariesTask.cs | 18 +- 8 files changed, 195 insertions(+), 262 deletions(-) delete mode 100644 Tranga/TrangaTasks/DownloadNewChaptersTask.cs create mode 100644 Tranga/TrangaTasks/MonitorPublicationTask.cs diff --git a/Tranga-API/Program.cs b/Tranga-API/Program.cs index 0092024..4213d59 100644 --- a/Tranga-API/Program.cs +++ b/Tranga-API/Program.cs @@ -112,14 +112,12 @@ app.MapPost("/Tasks/CreateMonitorTask", Publication? publication = taskManager.GetAllPublications().FirstOrDefault(pub => pub.internalId == internalId); if (publication is null) return; - taskManager.AddTask(new DownloadNewChaptersTask(TrangaTask.Task.DownloadNewChapters, connectorName, - (Publication)publication, - TimeSpan.Parse(reoccurrenceTime), language ?? "en")); + taskManager.AddTask(new MonitorPublicationTask(connectorName, (Publication)publication, TimeSpan.Parse(reoccurrenceTime), language ?? "en")); }); app.MapPost("/Tasks/CreateUpdateLibraryTask", (string reoccurrenceTime) => { - taskManager.AddTask(new UpdateLibrariesTask(TrangaTask.Task.UpdateLibraries, TimeSpan.Parse(reoccurrenceTime))); + taskManager.AddTask(new UpdateLibrariesTask(TimeSpan.Parse(reoccurrenceTime))); }); app.MapPost("/Tasks/CreateDownloadChaptersTask", (string connectorName, string internalId, string chapters, string? language) => { @@ -134,14 +132,14 @@ app.MapPost("/Tasks/CreateDownloadChaptersTask", (string connectorName, string i IEnumerable toDownload = connector.SearchChapters((Publication)publication, chapters, language ?? "en"); foreach(Chapter chapter in toDownload) - taskManager.AddTask(new DownloadChapterTask(TrangaTask.Task.DownloadChapter, connectorName, - (Publication)publication, chapter, "en")); + taskManager.AddTask(new DownloadChapterTask(connectorName, (Publication)publication, chapter, "en")); }); app.MapDelete("/Tasks/Delete", (string taskType, string? connectorName, string? publicationId) => { TrangaTask.Task task = Enum.Parse(taskType); - taskManager.DeleteTask(task, connectorName, publicationId); + foreach(TrangaTask tTask in taskManager.GetTasksMatching(task, connectorName, internalId: publicationId)) + taskManager.DeleteTask(tTask); }); app.MapGet("/Tasks/Get", (string taskType, string? connectorName, string? searchString) => @@ -167,7 +165,7 @@ app.MapGet("/Tasks/GetProgress", (string taskType, string connectorName, string { TrangaTask? task = null; TrangaTask.Task pTask = Enum.Parse(taskType); - if (pTask is TrangaTask.Task.DownloadNewChapters) + if (pTask is TrangaTask.Task.MonitorPublication) { task = taskManager.GetTasksMatching(pTask, connectorName: connectorName, internalId: publicationId).FirstOrDefault(); }else if (pTask is TrangaTask.Task.DownloadChapter && chapterSortNumber is not null) @@ -192,7 +190,7 @@ app.MapPost("/Tasks/Start", (string taskType, string? connectorName, string? int { TrangaTask.Task pTask = Enum.Parse(taskType); TrangaTask? task = taskManager - .GetTasksMatching(pTask, connectorName: connectorName, internalId: internalId)?.FirstOrDefault(); + .GetTasksMatching(pTask, connectorName: connectorName, internalId: internalId).FirstOrDefault(); if (task is null) return; @@ -217,7 +215,7 @@ app.MapPost("/Queue/Enqueue", (string taskType, string? connectorName, string? p { TrangaTask.Task pTask = Enum.Parse(taskType); TrangaTask? task = taskManager - .GetTasksMatching(pTask, connectorName: connectorName, internalId: publicationId)?.First(); + .GetTasksMatching(pTask, connectorName: connectorName, internalId: publicationId).FirstOrDefault(); if (task is null) return; @@ -235,7 +233,7 @@ app.MapDelete("/Queue/Dequeue", (string taskType, string? connectorName, string? { TrangaTask.Task pTask = Enum.Parse(taskType); TrangaTask? task = taskManager - .GetTasksMatching(pTask, connectorName: connectorName, internalId: publicationId)?.First(); + .GetTasksMatching(pTask, connectorName: connectorName, internalId: publicationId).FirstOrDefault(); if (task is null) return; diff --git a/Tranga-CLI/Tranga_Cli.cs b/Tranga-CLI/Tranga_Cli.cs index e0267a1..060cb8a 100644 --- a/Tranga-CLI/Tranga_Cli.cs +++ b/Tranga-CLI/Tranga_Cli.cs @@ -335,8 +335,9 @@ public static class Tranga_Cli TimeSpan reoccurrence = SelectReoccurrence(logger); logger.WriteLine("Tranga_CLI", "Sending Task to TaskManager"); - TrangaTask? newTask = taskManager.AddTask(TrangaTask.Task.DownloadNewChapters, connector.name, publication.Value.publicationId, reoccurrence, "en"); - Console.WriteLine(newTask); + TrangaTask nTask = new MonitorPublicationTask(connector.name, (Publication)publication, reoccurrence, "en"); + taskManager.AddTask(nTask); + Console.WriteLine(nTask); } private static void AddTaskToQueue(TaskManager taskManager, Logger logger) @@ -408,20 +409,19 @@ public static class Tranga_Cli return; } - if (task is TrangaTask.Task.DownloadNewChapters) + if (task is TrangaTask.Task.MonitorPublication) { TimeSpan reoccurrence = SelectReoccurrence(logger); logger.WriteLine("Tranga_CLI", "Sending Task to TaskManager"); - TrangaTask newTask = new DownloadNewChaptersTask(TrangaTask.Task.DownloadNewChapters, connector!.name, (Publication)publication!, reoccurrence, "en"); + TrangaTask newTask = new MonitorPublicationTask(connector!.name, (Publication)publication!, reoccurrence, "en"); taskManager.AddTask(newTask); Console.WriteLine(newTask); }else if (task is TrangaTask.Task.DownloadChapter) { foreach (Chapter chapter in SelectChapters(connector!, (Publication)publication!, logger)) { - TrangaTask newTask = new DownloadChapterTask(TrangaTask.Task.DownloadChapter, connector!.name, - (Publication)publication!, chapter, "en"); + TrangaTask newTask = new DownloadChapterTask(connector!.name, (Publication)publication, chapter, "en"); taskManager.AddTask(newTask); Console.WriteLine(newTask); } diff --git a/Tranga/TaskManager.cs b/Tranga/TaskManager.cs index 23fbd3d..e82c089 100644 --- a/Tranga/TaskManager.cs +++ b/Tranga/TaskManager.cs @@ -20,17 +20,6 @@ public class TaskManager private readonly Dictionary _runningDownloadChapterTasks = new(); - /// Local path to save data (Manga) to - /// Path to the working directory - /// Path to the cover-image cache - /// - /// - /// - public TaskManager(string downloadFolderPath, string workingDirectory, string imageCachePath, HashSet libraryManagers, HashSet notificationManagers, Logger? logger = null) : this(new TrangaSettings(downloadFolderPath, workingDirectory, libraryManagers, notificationManagers), logger) - { - - } - public TaskManager(TrangaSettings settings, Logger? logger = null) { this.logger = logger; @@ -65,54 +54,47 @@ public class TaskManager waitingButExecute.state = TrangaTask.ExecutionState.Enqueued; } - foreach (TrangaTask task in _allTasks.Where(enqueuedTask => enqueuedTask.state is TrangaTask.ExecutionState.Enqueued)) + foreach (TrangaTask enqueuedTask in _allTasks.Where(enqueuedTask => enqueuedTask.state is TrangaTask.ExecutionState.Enqueued)) { - switch (task.task) + switch (enqueuedTask.task) { - case TrangaTask.Task.DownloadNewChapters: - if (!_allTasks.Any(taskQuery => - taskQuery.task == TrangaTask.Task.DownloadNewChapters && - taskQuery.state is TrangaTask.ExecutionState.Running && - ((DownloadNewChaptersTask)taskQuery).connectorName == ((DownloadNewChaptersTask)task).connectorName)) - { - ExecuteTaskNow(task); - } - break; case TrangaTask.Task.DownloadChapter: + case TrangaTask.Task.MonitorPublication: if (!_allTasks.Any(taskQuery => - taskQuery.task == TrangaTask.Task.DownloadChapter && - taskQuery.state is TrangaTask.ExecutionState.Running && - ((DownloadChapterTask)taskQuery).connectorName == ((DownloadChapterTask)task).connectorName)) + { + if (taskQuery.state is not TrangaTask.ExecutionState.Running) return false; + switch (taskQuery) + { + case DownloadChapterTask dct when enqueuedTask is DownloadChapterTask eDct && dct.connectorName == eDct.connectorName: + case MonitorPublicationTask mpt when enqueuedTask is MonitorPublicationTask eMpt && mpt.connectorName == eMpt.connectorName: + return true; + default: + return false; + } + })) { - ExecuteTaskNow(task); + ExecuteTaskNow(enqueuedTask); } break; case TrangaTask.Task.UpdateLibraries: - ExecuteTaskNow(task); + ExecuteTaskNow(enqueuedTask); break; } } - HashSet failedToRemove = new(); - foreach (KeyValuePair removeTask in _runningDownloadChapterTasks) + foreach (TrangaTask failedTask in _allTasks.Where(taskQuery => + taskQuery.state is TrangaTask.ExecutionState.Failed)) { - if (removeTask.Key.GetType() == typeof(DownloadChapterTask) && - DateTime.Now.Subtract(removeTask.Key.lastChange) > TimeSpan.FromMinutes(3))//3 Minutes since last update to task -> remove + switch (failedTask.task) { - logger?.WriteLine(this.GetType().ToString(), $"Disposing failed task {removeTask.Key}."); - removeTask.Value.Cancel(); - failedToRemove.Add(removeTask.Key); + case TrangaTask.Task.DownloadChapter: + DeleteTask(failedTask); + TrangaTask newTask = failedTask.Clone(); + failedTask.parentTask?.AddChildTask(newTask); + AddTask(newTask); + break; } } - foreach (DownloadChapterTask taskToRestart in failedToRemove) - { - DeleteTask(taskToRestart); - DownloadChapterTask newTask = new (taskToRestart.task, taskToRestart.connectorName, - taskToRestart.publication, taskToRestart.chapter, taskToRestart.language, - (DownloadNewChaptersTask?)taskToRestart.parentTask); - AddTask(newTask); - taskToRestart.parentTask?.ReplaceFailedChildTask(taskToRestart, newTask); - } if(waitingTasksCount != _allTasks.Count(task => task.state is TrangaTask.ExecutionState.Waiting)) ExportDataAndSettings(); @@ -150,23 +132,19 @@ public class TaskManager _allTasks.RemoveWhere(trangaTask => trangaTask.task is TrangaTask.Task.UpdateLibraries); _allTasks.Add(newTask); break; - case TrangaTask.Task.DownloadNewChapters: - IEnumerable matchingdnc = - _allTasks.Where(mTask => mTask.GetType() == typeof(DownloadNewChaptersTask)); - if (!matchingdnc.Any(mTask => - ((DownloadNewChaptersTask)mTask).publication.internalId == ((DownloadNewChaptersTask)newTask).publication.internalId && - ((DownloadNewChaptersTask)mTask).connectorName == ((DownloadNewChaptersTask)newTask).connectorName)) + case TrangaTask.Task.MonitorPublication: + if (!_allTasks.Any(mTask => mTask is MonitorPublicationTask mpt && newTask is MonitorPublicationTask nMpt && + mpt.publication.internalId == nMpt.publication.internalId && + mpt.connectorName == nMpt.connectorName)) _allTasks.Add(newTask); else logger?.WriteLine(this.GetType().ToString(), $"Task already exists {newTask}"); break; case TrangaTask.Task.DownloadChapter: - IEnumerable matchingdc = - _allTasks.Where(mTask => mTask.GetType() == typeof(DownloadChapterTask)); - if (!matchingdc.Any(mTask => - ((DownloadChapterTask)mTask).publication.internalId == ((DownloadChapterTask)newTask).publication.internalId && - ((DownloadChapterTask)mTask).connectorName == ((DownloadChapterTask)newTask).connectorName && - ((DownloadChapterTask)mTask).chapter.sortNumber == ((DownloadChapterTask)newTask).chapter.sortNumber)) + if (!_allTasks.Any(mTask => mTask is DownloadChapterTask dct && newTask is DownloadChapterTask nDct && + dct.publication.internalId == nDct.publication.internalId && + dct.connectorName == nDct.connectorName && + dct.chapter.sortNumber == nDct.chapter.sortNumber)) _allTasks.Add(newTask); else logger?.WriteLine(this.GetType().ToString(), $"Task already exists {newTask}"); @@ -179,130 +157,60 @@ public class TaskManager { logger?.WriteLine(this.GetType().ToString(), $"Removing Task {removeTask}"); _allTasks.Remove(removeTask); - if (removeTask.parentTask is not null) - removeTask.parentTask.RemoveChildTask(removeTask); - if (removeTask.GetType() == typeof(DownloadChapterTask) && _runningDownloadChapterTasks.ContainsKey((DownloadChapterTask)removeTask)) + removeTask.parentTask?.RemoveChildTask(removeTask); + if (removeTask is DownloadChapterTask cRemoveTask && _runningDownloadChapterTasks.ContainsKey(cRemoveTask)) { - _runningDownloadChapterTasks[(DownloadChapterTask)removeTask].Cancel(); - _runningDownloadChapterTasks.Remove((DownloadChapterTask)removeTask); + _runningDownloadChapterTasks[cRemoveTask].Cancel(); + _runningDownloadChapterTasks.Remove(cRemoveTask); } } - public TrangaTask? AddTask(TrangaTask.Task taskType, string? connectorName, string? internalId, - TimeSpan reoccurrenceTime, string? language = "en") - { - TrangaTask? newTask = null; - switch (taskType) - { - case TrangaTask.Task.UpdateLibraries: - newTask = new UpdateLibrariesTask(taskType, reoccurrenceTime); - break; - case TrangaTask.Task.DownloadNewChapters: - if (connectorName is null) - logger?.WriteLine(this.GetType().ToString(), $"Value connectorName can not be null."); - if(internalId is null) - logger?.WriteLine(this.GetType().ToString(), $"Value internalId can not be null."); - if(language is null) - logger?.WriteLine(this.GetType().ToString(), $"Value language can not be null."); - if (connectorName is null || internalId is null || language is null) - return null; - GetConnector(connectorName); //Check if connectorName is valid - Publication publication = GetAllPublications().First(pub => pub.internalId == internalId); - newTask = new DownloadNewChaptersTask(taskType, connectorName!, publication, reoccurrenceTime, language!); - break; - } - if(newTask is not null) - AddTask(newTask); - return newTask; - } - - /// - /// Removes Task from task-collection - /// - /// TrangaTask.Task type - /// Name of Connector that was used - /// Publication that was used - public void DeleteTask(TrangaTask.Task task, string? connectorName, string? publicationId) - { - logger?.WriteLine(this.GetType().ToString(), $"Removing Task {task} {publicationId}"); - - switch (task) - { - case TrangaTask.Task.UpdateLibraries: - //Only one UpdateKomgaLibrary Task - logger?.WriteLine(this.GetType().ToString(), $"Removing old {task}-Task."); - _allTasks.RemoveWhere(trangaTask => trangaTask.task is TrangaTask.Task.UpdateLibraries); - break; - case TrangaTask.Task.DownloadNewChapters: - if (connectorName is null || publicationId is null) - logger?.WriteLine(this.GetType().ToString(), "connectorName and publication can not be null"); - else - { - _allTasks.RemoveWhere(mTask => - mTask.GetType() == typeof(DownloadNewChaptersTask) && - ((DownloadNewChaptersTask)mTask).publication.internalId == publicationId && - ((DownloadNewChaptersTask)mTask).connectorName == connectorName); - foreach(TrangaTask rTask in _allTasks.Where(mTask => - mTask.GetType() == typeof(DownloadChapterTask) && - ((DownloadChapterTask)mTask).publication.internalId == publicationId && - ((DownloadChapterTask)mTask).connectorName == connectorName)) - DeleteTask(rTask); - } - break; - } - ExportDataAndSettings(); - } - public IEnumerable GetTasksMatching(TrangaTask.Task taskType, string? connectorName = null, string? searchString = null, string? internalId = null, string? chapterSortNumber = null) { switch (taskType) { case TrangaTask.Task.UpdateLibraries: return _allTasks.Where(tTask => tTask.task == TrangaTask.Task.UpdateLibraries); - case TrangaTask.Task.DownloadNewChapters: + case TrangaTask.Task.MonitorPublication: if(connectorName is null) return _allTasks.Where(tTask => tTask.task == taskType); GetConnector(connectorName);//Name check - IEnumerable matchingdnc = _allTasks.Where(tTask => tTask.GetType() == typeof(DownloadNewChaptersTask)); if (searchString is not null) { - return matchingdnc.Where(mTask => - ((DownloadNewChaptersTask)mTask).connectorName == connectorName && - ((DownloadNewChaptersTask)mTask).ToString().Contains(searchString, StringComparison.InvariantCultureIgnoreCase)); + return _allTasks.Where(mTask => + mTask is MonitorPublicationTask mpt && mpt.connectorName == connectorName && + mpt.ToString().Contains(searchString, StringComparison.InvariantCultureIgnoreCase)); } else if (internalId is not null) { - return matchingdnc.Where(mTask => - ((DownloadNewChaptersTask)mTask).connectorName == connectorName && - ((DownloadNewChaptersTask)mTask).publication.internalId == internalId); + return _allTasks.Where(mTask => + mTask is MonitorPublicationTask mpt && mpt.connectorName == connectorName && + mpt.publication.internalId == internalId); } else return _allTasks.Where(tTask => - tTask.GetType() == typeof(DownloadNewChaptersTask) && - ((DownloadNewChaptersTask)tTask).connectorName == connectorName); + tTask is MonitorPublicationTask mpt && mpt.connectorName == connectorName); case TrangaTask.Task.DownloadChapter: if(connectorName is null) return _allTasks.Where(tTask => tTask.task == taskType); GetConnector(connectorName);//Name check - IEnumerable matchingdc = _allTasks.Where(tTask => tTask.GetType() == typeof(DownloadChapterTask)); if (searchString is not null) { - return matchingdc.Where(mTask => - ((DownloadChapterTask)mTask).connectorName == connectorName && - ((DownloadChapterTask)mTask).ToString().Contains(searchString, StringComparison.InvariantCultureIgnoreCase)); + return _allTasks.Where(mTask => + mTask is DownloadChapterTask dct && dct.connectorName == connectorName && + dct.ToString().Contains(searchString, StringComparison.InvariantCultureIgnoreCase)); } else if (internalId is not null && chapterSortNumber is not null) { - return matchingdc.Where(mTask => - ((DownloadChapterTask)mTask).connectorName == connectorName && - ((DownloadChapterTask)mTask).publication.publicationId == internalId && - ((DownloadChapterTask)mTask).chapter.sortNumber == chapterSortNumber); + return _allTasks.Where(mTask => + mTask is DownloadChapterTask dct && dct.connectorName == connectorName && + dct.publication.publicationId == internalId && + dct.chapter.sortNumber == chapterSortNumber); } else - return _allTasks.Where(tTask => - tTask.GetType() == typeof(DownloadChapterTask) && - ((DownloadChapterTask)tTask).connectorName == connectorName); + return _allTasks.Where(mTask => + mTask is DownloadChapterTask dct && dct.connectorName == connectorName); default: return Array.Empty(); diff --git a/Tranga/TrangaTask.cs b/Tranga/TrangaTask.cs index e55bf34..a2d66f8 100644 --- a/Tranga/TrangaTask.cs +++ b/Tranga/TrangaTask.cs @@ -11,7 +11,7 @@ namespace Tranga; /// /// Stores information on Task, when implementing new Tasks also update the serializer /// -[JsonDerivedType(typeof(DownloadNewChaptersTask), 2)] +[JsonDerivedType(typeof(MonitorPublicationTask), 2)] [JsonDerivedType(typeof(UpdateLibrariesTask), 3)] [JsonDerivedType(typeof(DownloadChapterTask), 4)] public abstract class TrangaTask @@ -20,27 +20,27 @@ public abstract class TrangaTask // ReSharper disable once MemberCanBePrivate.Global I want it thaaat way public TimeSpan reoccurrence { get; } public DateTime lastExecuted { get; set; } - public Task task { get; } - public string taskId { get; set; } [Newtonsoft.Json.JsonIgnore] public ExecutionState state { get; set; } - [Newtonsoft.Json.JsonIgnore] protected HashSet childTasks { get; } + public Task task { get; } + public string taskId { get; } [Newtonsoft.Json.JsonIgnore] public TrangaTask? parentTask { get; set; } public string? parentTaskId { get; set; } - [Newtonsoft.Json.JsonIgnore]public double progress { get; private set; } + [Newtonsoft.Json.JsonIgnore] protected HashSet childTasks { get; } + [Newtonsoft.Json.JsonIgnore] public double progress => GetProgress(); [Newtonsoft.Json.JsonIgnore]public DateTime executionStarted { get; private set; } [Newtonsoft.Json.JsonIgnore]public DateTime lastChange { get; private set; } [Newtonsoft.Json.JsonIgnore]public DateTime executionApproximatelyFinished => progress != 0 ? lastChange.Add(GetRemainingTime()) : DateTime.MaxValue; [Newtonsoft.Json.JsonIgnore]public TimeSpan executionApproximatelyRemaining => executionApproximatelyFinished.Subtract(DateTime.Now); [Newtonsoft.Json.JsonIgnore]public DateTime nextExecution => lastExecuted.Add(reoccurrence); - public enum ExecutionState { Waiting, Enqueued, Running } + public enum ExecutionState { Waiting, Enqueued, Running, Failed } protected TrangaTask(Task task, TimeSpan reoccurrence, TrangaTask? parentTask = null) { this.reoccurrence = reoccurrence; this.lastExecuted = DateTime.Now.Subtract(reoccurrence); this.task = task; - this.executionStarted = DateTime.Now; + this.executionStarted = DateTime.UnixEpoch; this.lastChange = DateTime.MaxValue; this.taskId = Convert.ToBase64String(BitConverter.GetBytes(new Random().Next())); this.childTasks = new(); @@ -54,7 +54,11 @@ public abstract class TrangaTask /// /// /// - protected abstract void ExecuteTask(TaskManager taskManager, Logger? logger, CancellationToken? cancellationToken = null); + protected abstract bool ExecuteTask(TaskManager taskManager, Logger? logger, CancellationToken? cancellationToken = null); + + public abstract TrangaTask Clone(); + + protected abstract double GetProgress(); /// /// Execute the task @@ -68,20 +72,22 @@ public abstract class TrangaTask this.state = ExecutionState.Running; this.executionStarted = DateTime.Now; this.lastChange = DateTime.Now; - ExecuteTask(taskManager, logger, cancellationToken); + bool success = ExecuteTask(taskManager, logger, cancellationToken); while(childTasks.Any(ct => ct.state is ExecutionState.Enqueued or ExecutionState.Running)) Thread.Sleep(1000); - this.lastExecuted = DateTime.Now; - this.state = ExecutionState.Waiting; + if (success) + { + this.lastExecuted = DateTime.Now; + this.state = ExecutionState.Waiting; + } + else + { + this.lastExecuted = DateTime.MaxValue; + this.state = ExecutionState.Failed; + } logger?.WriteLine(this.GetType().ToString(), $"Finished Executing Task {this}"); } - public void ReplaceFailedChildTask(DownloadChapterTask failed, DownloadChapterTask newTask) - { - this.RemoveChildTask(failed); - this.AddChildTask(newTask); - } - public void AddChildTask(TrangaTask childTask) { this.childTasks.Add(childTask); @@ -90,40 +96,22 @@ public abstract class TrangaTask public void RemoveChildTask(TrangaTask childTask) { this.childTasks.Remove(childTask); - this.DecrementProgress(childTask.progress); - } - - public void IncrementProgress(double amount) - { - this.lastChange = DateTime.Now; - this.progress += amount / (childTasks.Count > 0 ? childTasks.Count : 1); - if (parentTask is not null) - { - parentTask.IncrementProgress(amount); - parentTask.state = ExecutionState.Running; - } - } - - public void DecrementProgress(double amount) - { - this.lastChange = DateTime.Now; - this.progress -= amount / childTasks.Count > 0 ? childTasks.Count : 1; - parentTask?.DecrementProgress(amount); } private TimeSpan GetRemainingTime() { - if(progress == 0) - return DateTime.MaxValue.Subtract(DateTime.Now); + if(progress == 0 || lastChange > executionStarted) + return DateTime.MaxValue.Subtract(DateTime.Now.AddYears(1)); TimeSpan elapsed = lastChange.Subtract(executionStarted); return elapsed.Divide(progress).Subtract(elapsed); } public enum Task : byte { - DownloadNewChapters = 2, + MonitorPublication = 2, UpdateLibraries = 3, - DownloadChapter = 4 + DownloadChapter = 4, + DownloadNewChapters = 2 //legacy } public override string ToString() @@ -135,14 +123,14 @@ public abstract class TrangaTask { public override bool CanConvert(Type objectType) { - return (objectType == typeof(TrangaTask)); + return objectType == typeof(TrangaTask); } public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { JObject jo = JObject.Load(reader); - if (jo["task"]!.Value() == (Int64)Task.DownloadNewChapters) - return jo.ToObject(serializer)!; + if (jo["task"]!.Value() == (Int64)Task.MonitorPublication) + return jo.ToObject(serializer)!; if (jo["task"]!.Value() == (Int64)Task.UpdateLibraries) return jo.ToObject(serializer)!; diff --git a/Tranga/TrangaTasks/DownloadChapterTask.cs b/Tranga/TrangaTasks/DownloadChapterTask.cs index e23bc4d..f998be6 100644 --- a/Tranga/TrangaTasks/DownloadChapterTask.cs +++ b/Tranga/TrangaTasks/DownloadChapterTask.cs @@ -10,7 +10,9 @@ public class DownloadChapterTask : TrangaTask public string language { get; } public Chapter chapter { get; } - public DownloadChapterTask(Task task, string connectorName, Publication publication, Chapter chapter, string language = "en", DownloadNewChaptersTask? parentTask = null) : base(task, TimeSpan.Zero, parentTask) + private double _dctProgress = 0; + + public DownloadChapterTask(string connectorName, Publication publication, Chapter chapter, string language = "en", MonitorPublicationTask? parentTask = null) : base(Task.DownloadChapter, TimeSpan.Zero, parentTask) { this.chapter = chapter; this.connectorName = connectorName; @@ -18,21 +20,34 @@ public class DownloadChapterTask : TrangaTask this.language = language; } - protected override void ExecuteTask(TaskManager taskManager, Logger? logger, CancellationToken? cancellationToken = null) + protected override bool ExecuteTask(TaskManager taskManager, Logger? logger, CancellationToken? cancellationToken = null) { if (cancellationToken?.IsCancellationRequested??false) - return; - if(this.parentTask is not null) - this.parentTask.state = ExecutionState.Running; + return false; Connector connector = taskManager.GetConnector(this.connectorName); connector.CopyCoverFromCacheToDownloadLocation(this.publication, taskManager.settings); bool downloadSuccess = connector.DownloadChapter(this.publication, this.chapter, this, cancellationToken); - if(this.parentTask is not null) - this.parentTask.state = ExecutionState.Waiting; taskManager.DeleteTask(this); if(downloadSuccess && parentTask is not null) foreach(NotificationManager nm in taskManager.settings.notificationManagers) nm.SendNotification("New Chapter downloaded", $"{this.publication.sortName} {this.chapter.chapterNumber} {this.chapter.name}"); + return downloadSuccess; + } + + public override TrangaTask Clone() + { + return new DownloadChapterTask(this.connectorName, this.publication, this.chapter, + this.language, (MonitorPublicationTask?)this.parentTask); + } + + protected override double GetProgress() + { + return _dctProgress; + } + + internal void IncrementProgress(double amount) + { + this._dctProgress += amount; } public override string ToString() diff --git a/Tranga/TrangaTasks/DownloadNewChaptersTask.cs b/Tranga/TrangaTasks/DownloadNewChaptersTask.cs deleted file mode 100644 index 172a2b3..0000000 --- a/Tranga/TrangaTasks/DownloadNewChaptersTask.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Logging; - -namespace Tranga.TrangaTasks; - -public class DownloadNewChaptersTask : TrangaTask -{ - public string connectorName { get; } - public Publication publication { get; } - public string language { get; } - public DownloadNewChaptersTask(Task task, string connectorName, Publication publication, TimeSpan reoccurrence, string language = "en") : base(task, reoccurrence) - { - this.connectorName = connectorName; - this.publication = publication; - this.language = language; - } - - protected override void ExecuteTask(TaskManager taskManager, Logger? logger, CancellationToken? cancellationToken = null) - { - if (cancellationToken?.IsCancellationRequested??false) - return; - Publication pub = publication!; - Connector connector = taskManager.GetConnector(this.connectorName); - - //Check if Publication already has a Folder - pub.CreatePublicationFolder(taskManager.settings.downloadLocation); - List newChapters = taskManager.GetNewChaptersList(connector, pub, language!); - - connector.CopyCoverFromCacheToDownloadLocation(pub, taskManager.settings); - - pub.SaveSeriesInfoJson(connector.downloadLocation); - - foreach (Chapter newChapter in newChapters) - { - DownloadChapterTask newTask = new (Task.DownloadChapter, this.connectorName, pub, newChapter, this.language, this); - this.childTasks.Add(newTask); - newTask.state = ExecutionState.Enqueued; - taskManager.AddTask(newTask); - } - } - - public override string ToString() - { - return $"{base.ToString()}, {connectorName}, {publication.sortName} {publication.internalId}"; - } -} \ No newline at end of file diff --git a/Tranga/TrangaTasks/MonitorPublicationTask.cs b/Tranga/TrangaTasks/MonitorPublicationTask.cs new file mode 100644 index 0000000..a8b794a --- /dev/null +++ b/Tranga/TrangaTasks/MonitorPublicationTask.cs @@ -0,0 +1,59 @@ +using Logging; + +namespace Tranga.TrangaTasks; + +public class MonitorPublicationTask : TrangaTask +{ + public string connectorName { get; } + public Publication publication { get; } + public string language { get; } + public MonitorPublicationTask(string connectorName, Publication publication, TimeSpan reoccurrence, string language = "en") : base(Task.MonitorPublication, reoccurrence) + { + this.connectorName = connectorName; + this.publication = publication; + this.language = language; + } + + protected override bool ExecuteTask(TaskManager taskManager, Logger? logger, CancellationToken? cancellationToken = null) + { + if (cancellationToken?.IsCancellationRequested??false) + return false; + Connector connector = taskManager.GetConnector(this.connectorName); + + //Check if Publication already has a Folder + publication.CreatePublicationFolder(taskManager.settings.downloadLocation); + List newChapters = taskManager.GetNewChaptersList(connector, publication, language); + + connector.CopyCoverFromCacheToDownloadLocation(publication, taskManager.settings); + + publication.SaveSeriesInfoJson(connector.downloadLocation); + + foreach (Chapter newChapter in newChapters) + { + DownloadChapterTask newTask = new (this.connectorName, publication, newChapter, this.language, this); + this.childTasks.Add(newTask); + newTask.state = ExecutionState.Enqueued; + taskManager.AddTask(newTask); + } + + return true; + } + + public override TrangaTask Clone() + { + return new MonitorPublicationTask(this.connectorName, this.publication, this.reoccurrence, + this.language); + } + + protected override double GetProgress() + { + if (this.childTasks.Count > 0) + return this.childTasks.Sum(ct => ct.progress) / childTasks.Count; + return 1; + } + + public override string ToString() + { + return $"{base.ToString()}, {connectorName}, {publication.sortName} {publication.internalId}"; + } +} \ No newline at end of file diff --git a/Tranga/TrangaTasks/UpdateLibrariesTask.cs b/Tranga/TrangaTasks/UpdateLibrariesTask.cs index 35a90bc..fa00b38 100644 --- a/Tranga/TrangaTasks/UpdateLibrariesTask.cs +++ b/Tranga/TrangaTasks/UpdateLibrariesTask.cs @@ -4,16 +4,26 @@ namespace Tranga.TrangaTasks; public class UpdateLibrariesTask : TrangaTask { - public UpdateLibrariesTask(Task task, TimeSpan reoccurrence) : base(task, reoccurrence) + public UpdateLibrariesTask(TimeSpan reoccurrence) : base(Task.UpdateLibraries, reoccurrence) { } - protected override void ExecuteTask(TaskManager taskManager, Logger? logger, CancellationToken? cancellationToken = null) + protected override bool ExecuteTask(TaskManager taskManager, Logger? logger, CancellationToken? cancellationToken = null) { if (cancellationToken?.IsCancellationRequested??false) - return; + return false; foreach(LibraryManager lm in taskManager.settings.libraryManagers) lm.UpdateLibrary(); - IncrementProgress(1); + return true; + } + + public override TrangaTask Clone() + { + return new UpdateLibrariesTask(this.reoccurrence); + } + + protected override double GetProgress() + { + return 1; } } \ No newline at end of file