diff --git a/Tranga/Server/Server.cs b/Tranga/Server/Server.cs index 2386e1e..dba7a57 100644 --- a/Tranga/Server/Server.cs +++ b/Tranga/Server/Server.cs @@ -200,43 +200,31 @@ public partial class Server : GlobalBase, IDisposable response.AddHeader("Access-Control-Max-Age", "1728000"); response.AppendHeader("Access-Control-Allow-Origin", "*"); - if (content is not Stream) + + try { - response.ContentType = "application/json"; - try + if (content is Stream stream) { + response.ContentType = "image/jpeg"; + response.AddHeader("Cache-Control", "max-age=600"); + stream.CopyTo(response.OutputStream); + response.OutputStream.Close(); + stream.Close(); + } + else + { + response.ContentType = "application/json"; + response.AddHeader("Cache-Control", "no-store"); response.OutputStream.Write(content is not null ? Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(content)) : Array.Empty()); - response.OutputStream.Close(); } - catch (HttpListenerException e) - { - Log(e.ToString()); - } - } - else if(content is FileStream stream) - { - string contentType = stream.Name.Split('.')[^1]; - switch (contentType.ToLower()) - { - case "gif": - response.ContentType = "image/gif"; - break; - case "png": - response.ContentType = "image/png"; - break; - case "jpg": - case "jpeg": - response.ContentType = "image/jpeg"; - break; - default: - response.ContentType = "text/plain"; - break; - } - stream.CopyTo(response.OutputStream); + response.OutputStream.Close(); - stream.Close(); + } + catch (HttpListenerException e) + { + Log(e.ToString()); } } diff --git a/Tranga/Server/v2Manga.cs b/Tranga/Server/v2Manga.cs index 749e95e..2528cba 100644 --- a/Tranga/Server/v2Manga.cs +++ b/Tranga/Server/v2Manga.cs @@ -1,4 +1,6 @@ -using System.Net; +using System.Drawing; +using System.Drawing.Imaging; +using System.Net; using System.Text.RegularExpressions; using Tranga.Jobs; using Tranga.MangaConnectors; @@ -77,12 +79,37 @@ public partial class Server manga is null) return new ValueTuple(HttpStatusCode.NotFound, $"Manga with ID '{groups[1].Value} could not be found.'"); string filePath = manga.Value.coverFileNameInCache!; - if (File.Exists(filePath)) + if(!File.Exists(filePath)) + return new ValueTuple(HttpStatusCode.NotFound, "Cover-File not found."); + + Bitmap bitmap; + if (requestParameters.TryGetValue("dimensions", out string? dimensionsStr)) + { + Regex dimensionsRex = new(@"([0-9]+)x([0-9]+)"); + if(!dimensionsRex.IsMatch(dimensionsStr)) + return new ValueTuple(HttpStatusCode.BadRequest, "Requested dimensions not in required format."); + Match m = dimensionsRex.Match(dimensionsStr); + int width = int.Parse(m.Groups[1].Value); + int height = int.Parse(m.Groups[2].Value); + double aspectRequested = (double)width / (double)height; + + using Image coverImage = Image.FromFile(filePath); + double aspectCover = (double)coverImage.Width / (double)coverImage.Height; + + Size newSize = aspectRequested > aspectCover + ? new Size(width, (width / coverImage.Width) * coverImage.Height) + : new Size((height / coverImage.Height) * coverImage.Width, height); + + bitmap = new(coverImage, newSize); + } + else { FileStream coverStream = new(filePath, FileMode.Open); - return new ValueTuple(HttpStatusCode.OK, coverStream); + bitmap = new(coverStream); } - return new ValueTuple(HttpStatusCode.NotFound, "Cover-File not found."); + using MemoryStream ret = new(); + bitmap.Save(ret, ImageFormat.Jpeg); + return new ValueTuple(HttpStatusCode.OK, ret); } private ValueTuple GetV2MangaInternalIdChapters(GroupCollection groups, Dictionary requestParameters) diff --git a/Tranga/Tranga.csproj b/Tranga/Tranga.csproj index 58cb6de..cc66d5a 100644 --- a/Tranga/Tranga.csproj +++ b/Tranga/Tranga.csproj @@ -13,6 +13,7 @@ + diff --git a/docs/API_Calls_v2.md b/docs/API_Calls_v2.md index 5e32b61..4acbf83 100644 --- a/docs/API_Calls_v2.md +++ b/docs/API_Calls_v2.md @@ -186,12 +186,16 @@ Returns the URL for the Cover of the specified Manga. * [GET /v2/Manga](#-v2manga) * [GET /v2/Connector/*ConnectorName*/GetManga](#-v2connectorconnectornamegetmanga) * [GET /v2/Job/*jobId*](#-v2jobjobid) + + Optional: `dimensions=x` replace width and height with requested dimensions in pixels. + Fitting will cover requested area.
Returns String with the url. +If `dimensions=x` was not requested, returns full sized image. | StatusCode | Meaning | |------------|--------------------------------------------|