From 23dfdc093324816a9517670515e3c832e4751a9f Mon Sep 17 00:00:00 2001 From: glax Date: Mon, 19 Jun 2023 22:45:33 +0200 Subject: [PATCH] Connector DownloadChapter, DownloadImage, DownloadChapterImages returns successState. RequestResult replace HttpStatusCode with success-status boolean. DownloadChapterTask: Only send Notification when Chapter download successful --- Tranga/Connector.cs | 43 ++++++++++++----------- Tranga/Connectors/MangaDex.cs | 20 +++++------ Tranga/Connectors/Manganato.cs | 16 ++++----- Tranga/Connectors/Mangasee.cs | 16 +++++---- Tranga/TrangaTasks/DownloadChapterTask.cs | 4 +-- 5 files changed, 52 insertions(+), 47 deletions(-) diff --git a/Tranga/Connector.cs b/Tranga/Connector.cs index cdce71d..ffdf05b 100644 --- a/Tranga/Connector.cs +++ b/Tranga/Connector.cs @@ -134,7 +134,7 @@ public abstract class Connector /// Chapter with Images to retrieve /// Will be used for progress-tracking /// - public abstract void DownloadChapter(Publication publication, Chapter chapter, DownloadChapterTask parentTask, CancellationToken? cancellationToken = null); + public abstract bool DownloadChapter(Publication publication, Chapter chapter, DownloadChapterTask parentTask, CancellationToken? cancellationToken = null); /// /// Copies the already downloaded cover from cache to downloadLocation @@ -213,16 +213,15 @@ public abstract class Connector /// /// RequestType for Rate-Limit /// referrer used in html request header - private void DownloadImage(string imageUrl, string fullPath, byte requestType, string? referrer = null) + private bool DownloadImage(string imageUrl, string fullPath, byte requestType, string? referrer = null) { DownloadClient.RequestResult requestResult = downloadClient.MakeRequest(imageUrl, requestType, referrer); - if (requestResult.result != Stream.Null) - { - byte[] buffer = new byte[requestResult.result.Length]; - requestResult.result.ReadExactly(buffer, 0, buffer.Length); - File.WriteAllBytes(fullPath, buffer); - }else - logger?.WriteLine(this.GetType().ToString(), "No Stream-Content in result."); + if (!requestResult.success || requestResult.result == Stream.Null) + return false; + byte[] buffer = new byte[requestResult.result.Length]; + requestResult.result.ReadExactly(buffer, 0, buffer.Length); + File.WriteAllBytes(fullPath, buffer); + return true; } /// @@ -234,10 +233,10 @@ public abstract class Connector /// Path of the generate Chapter ComicInfo.xml, if it was generated /// RequestType for RateLimits /// Used in http request header - protected void DownloadChapterImages(string[] imageUrls, string saveArchiveFilePath, byte requestType, DownloadChapterTask parentTask, string? comicInfoPath = null, string? referrer = null, CancellationToken? cancellationToken = null) + protected bool DownloadChapterImages(string[] imageUrls, string saveArchiveFilePath, byte requestType, DownloadChapterTask parentTask, string? comicInfoPath = null, string? referrer = null, CancellationToken? cancellationToken = null) { if (cancellationToken?.IsCancellationRequested??false) - return; + return false; logger?.WriteLine("Connector", $"Downloading Images for {saveArchiveFilePath}"); //Check if Publication Directory already exists string directoryPath = Path.GetDirectoryName(saveArchiveFilePath)!; @@ -245,7 +244,7 @@ public abstract class Connector Directory.CreateDirectory(directoryPath); if (File.Exists(saveArchiveFilePath)) //Don't download twice. - return; + return false; //Create a temporary folder to store images string tempFolder = Directory.CreateTempSubdirectory().FullName; @@ -257,10 +256,11 @@ public abstract class Connector string[] split = imageUrl.Split('.'); string extension = split[^1]; logger?.WriteLine("Connector", $"Downloading Image {chapter + 1:000}/{imageUrls.Length:000} {parentTask.publication.sortName} {parentTask.publication.internalId} Vol.{parentTask.chapter.volumeNumber} Ch.{parentTask.chapter.chapterNumber} {parentTask.progress:P2}"); - DownloadImage(imageUrl, Path.Join(tempFolder, $"{chapter++}.{extension}"), requestType, referrer); + if (!DownloadImage(imageUrl, Path.Join(tempFolder, $"{chapter++}.{extension}"), requestType, referrer)) + return false; parentTask.IncrementProgress(1.0 / imageUrls.Length); if (cancellationToken?.IsCancellationRequested??false) - return; + return false; } if(comicInfoPath is not null) @@ -272,6 +272,7 @@ public abstract class Connector if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) File.SetUnixFileMode(saveArchiveFilePath, GroupRead | GroupWrite | OtherRead | OtherWrite | UserRead | UserWrite); Directory.Delete(tempFolder, true); //Cleanup + return true; } protected string SaveCoverImageToCache(string url, byte requestType) @@ -327,7 +328,7 @@ public abstract class Connector else { logger?.WriteLine(this.GetType().ToString(), "RequestType not configured for rate-limit."); - return new RequestResult(HttpStatusCode.NotAcceptable, Stream.Null); + return new RequestResult(false, Stream.Null); } TimeSpan rateLimitTimeout = _rateLimit[requestType] @@ -354,20 +355,22 @@ public abstract class Connector Thread.Sleep(_rateLimit[requestType] * 2); } } - Stream resultString = response.IsSuccessStatusCode ? response.Content.ReadAsStream() : Stream.Null; if (!response.IsSuccessStatusCode) + { logger?.WriteLine(this.GetType().ToString(), $"Request-Error {response.StatusCode}: {response.ReasonPhrase}"); - return new RequestResult(response.StatusCode, resultString); + return new RequestResult(false, Stream.Null); + } + return new RequestResult(true, response.Content.ReadAsStream()); } public struct RequestResult { - public HttpStatusCode statusCode { get; } + public bool success { get; } public Stream result { get; } - public RequestResult(HttpStatusCode statusCode, Stream result) + public RequestResult(bool success, Stream result) { - this.statusCode = statusCode; + this.success = success; this.result = result; } } diff --git a/Tranga/Connectors/MangaDex.cs b/Tranga/Connectors/MangaDex.cs index b6c4b56..e56f5da 100644 --- a/Tranga/Connectors/MangaDex.cs +++ b/Tranga/Connectors/MangaDex.cs @@ -46,7 +46,7 @@ public class MangaDex : Connector DownloadClient.RequestResult requestResult = downloadClient.MakeRequest( $"https://api.mangadex.org/manga?limit={limit}&title={publicationTitle}&offset={offset}", (byte)RequestType.Manga); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) break; JsonObject? result = JsonSerializer.Deserialize(requestResult.result); @@ -165,7 +165,7 @@ public class MangaDex : Connector DownloadClient.RequestResult requestResult = downloadClient.MakeRequest( $"https://api.mangadex.org/manga/{publication.publicationId}/feed?limit={limit}&offset={offset}&translatedLanguage%5B%5D={language}", (byte)RequestType.Feed); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) break; JsonObject? result = JsonSerializer.Deserialize(requestResult.result); @@ -207,19 +207,19 @@ public class MangaDex : Connector return chapters.OrderBy(chapter => Convert.ToSingle(chapter.chapterNumber, chapterNumberFormatInfo)).ToArray(); } - public override void DownloadChapter(Publication publication, Chapter chapter, DownloadChapterTask parentTask, CancellationToken? cancellationToken = null) + public override bool DownloadChapter(Publication publication, Chapter chapter, DownloadChapterTask parentTask, CancellationToken? cancellationToken = null) { if (cancellationToken?.IsCancellationRequested??false) - return; + return false; logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}"); //Request URLs for Chapter-Images DownloadClient.RequestResult requestResult = downloadClient.MakeRequest($"https://api.mangadex.org/at-home/server/{chapter.url}?forcePort443=false'", (byte)RequestType.AtHomeServer); - if (requestResult.statusCode != HttpStatusCode.OK) - return; + if (!requestResult.success) + return false; JsonObject? result = JsonSerializer.Deserialize(requestResult.result); if (result is null) - return; + return false; string baseUrl = result["baseUrl"]!.GetValue(); string hash = result["chapter"]!["hash"]!.GetValue(); @@ -233,7 +233,7 @@ public class MangaDex : Connector File.WriteAllText(comicInfoPath, GetComicInfoXmlString(publication, chapter, logger)); //Download Chapter-Images - DownloadChapterImages(imageUrls.ToArray(), GetArchiveFilePath(publication, chapter), (byte)RequestType.AtHomeServer, parentTask, comicInfoPath, cancellationToken:cancellationToken); + return DownloadChapterImages(imageUrls.ToArray(), GetArchiveFilePath(publication, chapter), (byte)RequestType.AtHomeServer, parentTask, comicInfoPath, cancellationToken:cancellationToken); } private string? GetCoverUrl(string publicationId, string? posterId) @@ -248,7 +248,7 @@ public class MangaDex : Connector //Request information where to download Cover DownloadClient.RequestResult requestResult = downloadClient.MakeRequest($"https://api.mangadex.org/cover/{posterId}", (byte)RequestType.CoverUrl); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) return null; JsonObject? result = JsonSerializer.Deserialize(requestResult.result); if (result is null) @@ -268,7 +268,7 @@ public class MangaDex : Connector { DownloadClient.RequestResult requestResult = downloadClient.MakeRequest($"https://api.mangadex.org/author/{authorId}", (byte)RequestType.Author); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) return ret; JsonObject? result = JsonSerializer.Deserialize(requestResult.result); if (result is null) diff --git a/Tranga/Connectors/Manganato.cs b/Tranga/Connectors/Manganato.cs index 5085320..83b6e6d 100644 --- a/Tranga/Connectors/Manganato.cs +++ b/Tranga/Connectors/Manganato.cs @@ -27,7 +27,7 @@ public class Manganato : Connector string requestUrl = $"https://manganato.com/search/story/{sanitizedTitle}"; DownloadClient.RequestResult requestResult = downloadClient.MakeRequest(requestUrl, (byte)1); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) return Array.Empty(); return ParsePublicationsFromHtml(requestResult.result); @@ -52,7 +52,7 @@ public class Manganato : Connector { DownloadClient.RequestResult requestResult = downloadClient.MakeRequest(url, (byte)1); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) return Array.Empty(); ret.Add(ParseSinglePublicationFromHtml(requestResult.result, url.Split('/')[^1])); @@ -131,7 +131,7 @@ public class Manganato : Connector string requestUrl = $"https://chapmanganato.com/{publication.publicationId}"; DownloadClient.RequestResult requestResult = downloadClient.MakeRequest(requestUrl, (byte)1); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) return Array.Empty(); //Return Chapters ordered by Chapter-Number @@ -169,23 +169,23 @@ public class Manganato : Connector return ret; } - public override void DownloadChapter(Publication publication, Chapter chapter, DownloadChapterTask parentTask, CancellationToken? cancellationToken = null) + public override bool DownloadChapter(Publication publication, Chapter chapter, DownloadChapterTask parentTask, CancellationToken? cancellationToken = null) { if (cancellationToken?.IsCancellationRequested??false) - return; + return false; logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}"); string requestUrl = chapter.url; DownloadClient.RequestResult requestResult = downloadClient.MakeRequest(requestUrl, (byte)1); - if (requestResult.statusCode != HttpStatusCode.OK) - return; + if (!requestResult.success) + return false; string[] imageUrls = ParseImageUrlsFromHtml(requestResult.result); string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, GetComicInfoXmlString(publication, chapter, logger)); - DownloadChapterImages(imageUrls, GetArchiveFilePath(publication, chapter), (byte)1, parentTask, comicInfoPath, "https://chapmanganato.com/", cancellationToken); + return DownloadChapterImages(imageUrls, GetArchiveFilePath(publication, chapter), (byte)1, parentTask, comicInfoPath, "https://chapmanganato.com/", cancellationToken); } private string[] ParseImageUrlsFromHtml(Stream html) diff --git a/Tranga/Connectors/Mangasee.cs b/Tranga/Connectors/Mangasee.cs index 1a026c2..ec9f0fc 100644 --- a/Tranga/Connectors/Mangasee.cs +++ b/Tranga/Connectors/Mangasee.cs @@ -80,7 +80,7 @@ public class Mangasee : Connector string requestUrl = $"https://mangasee123.com/_search.php"; DownloadClient.RequestResult requestResult = downloadClient.MakeRequest(requestUrl, (byte)1); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) return Array.Empty(); return ParsePublicationsFromHtml(requestResult.result, publicationTitle); @@ -110,7 +110,7 @@ public class Mangasee : Connector { DownloadClient.RequestResult requestResult = downloadClient.MakeRequest($"https://mangasee123.com/manga/{orderedItem.i}", (byte)1); - if (requestResult.statusCode != HttpStatusCode.OK) + if (!requestResult.success) return Array.Empty(); ret.Add(ParseSinglePublicationFromHtml(requestResult.result, orderedItem.s, orderedItem.i, orderedItem.a)); } @@ -209,17 +209,17 @@ public class Mangasee : Connector return ret.OrderBy(chapter => Convert.ToSingle(chapter.chapterNumber, chapterNumberFormatInfo)).ToArray(); } - public override void DownloadChapter(Publication publication, Chapter chapter, DownloadChapterTask parentTask, CancellationToken? cancellationToken = null) + public override bool DownloadChapter(Publication publication, Chapter chapter, DownloadChapterTask parentTask, CancellationToken? cancellationToken = null) { - if (cancellationToken?.IsCancellationRequested??false) - return; + if (cancellationToken?.IsCancellationRequested ?? false) + return false; while (this._browser is null && !(cancellationToken?.IsCancellationRequested??false)) { logger?.WriteLine(this.GetType().ToString(), "Waiting for headless browser to download..."); Thread.Sleep(1000); } if (cancellationToken?.IsCancellationRequested??false) - return; + return false; logger?.WriteLine(this.GetType().ToString(), $"Downloading Chapter-Info {publication.sortName} {publication.internalId} {chapter.volumeNumber}-{chapter.chapterNumber}"); IPage page = _browser!.NewPageAsync().Result; @@ -238,7 +238,9 @@ public class Mangasee : Connector string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, GetComicInfoXmlString(publication, chapter, logger)); - DownloadChapterImages(urls.ToArray(), GetArchiveFilePath(publication, chapter), (byte)1, parentTask, comicInfoPath, cancellationToken:cancellationToken); + return DownloadChapterImages(urls.ToArray(), GetArchiveFilePath(publication, chapter), (byte)1, parentTask, comicInfoPath, cancellationToken:cancellationToken); } + + return false; } } \ No newline at end of file diff --git a/Tranga/TrangaTasks/DownloadChapterTask.cs b/Tranga/TrangaTasks/DownloadChapterTask.cs index 567d727..e23bc4d 100644 --- a/Tranga/TrangaTasks/DownloadChapterTask.cs +++ b/Tranga/TrangaTasks/DownloadChapterTask.cs @@ -26,11 +26,11 @@ public class DownloadChapterTask : TrangaTask this.parentTask.state = ExecutionState.Running; Connector connector = taskManager.GetConnector(this.connectorName); connector.CopyCoverFromCacheToDownloadLocation(this.publication, taskManager.settings); - connector.DownloadChapter(this.publication, this.chapter, this, cancellationToken); + 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(parentTask is not null) + 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}"); }