Compare commits

...

5 Commits

5 changed files with 76 additions and 13 deletions

View File

@ -96,26 +96,29 @@ public class MangaController(PgsqlContext context) : Controller
/// <response code="204">Cover not loaded</response>
/// <response code="400">The formatting-request was invalid</response>
/// <response code="404">Manga with ID not found</response>
/// <response code="503">Retry later, downloading cover</response>
[HttpGet("{MangaId}/Cover")]
[ProducesResponseType<byte[]>(Status200OK,"image/jpeg")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status400BadRequest)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType<int>(Status503ServiceUnavailable, "text/plain")]
public IActionResult GetCover(string MangaId, [FromQuery]int? width, [FromQuery]int? height)
{
DateTime requestStarted = HttpContext.Features.Get<IHttpRequestTimeFeature>()?.RequestTime ?? DateTime.Now;
Manga? m = context.Mangas.Find(MangaId);
if (m is null)
return NotFound();
if (!System.IO.File.Exists(m.CoverFileNameInCache))
{
bool coverIsBeingDownloaded = false;
do
List<Job> coverDownloadJobs = context.Jobs.Where(j => j.JobType == JobType.DownloadMangaCoverJob).ToList();
if (coverDownloadJobs.Any(j => j is DownloadMangaCoverJob dmc && dmc.MangaId == MangaId))
{
coverIsBeingDownloaded = context.Jobs.Where(j => j.JobType == JobType.DownloadMangaCoverJob).AsEnumerable()
.Any(j => j is DownloadMangaCoverJob dmcj && dmcj.MangaId == MangaId);
Thread.Sleep(100);
} while (coverIsBeingDownloaded);
if (!System.IO.File.Exists(m.CoverFileNameInCache))
Response.Headers.Add("Retry-After", $"{TrangaSettings.startNewJobTimeoutMs * coverDownloadJobs.Count() * 2 / 1000:D}");
return StatusCode(Status503ServiceUnavailable, TrangaSettings.startNewJobTimeoutMs * coverDownloadJobs.Count() * 2 / 1000);
}
else
return NoContent();
}
@ -212,11 +215,13 @@ public class MangaController(PgsqlContext context) : Controller
/// <response code="204">No available chapters</response>
/// <response code="404">Manga with ID not found.</response>
/// <response code="500">Could not retrieve the maximum chapter-number</response>
/// <response code="503">Retry after timeout, updating value</response>
[HttpGet("{MangaId}/Chapter/LatestAvailable")]
[ProducesResponseType<Chapter>(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType<string>(Status404NotFound, "text/plain")]
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
[ProducesResponseType<int>(Status503ServiceUnavailable, "text/plain")]
public IActionResult GetLatestChapter(string MangaId)
{
Manga? m = context.Mangas.Find(MangaId);
@ -225,7 +230,15 @@ public class MangaController(PgsqlContext context) : Controller
List<Chapter> chapters = context.Chapters.Where(c => c.ParentMangaId == m.MangaId).ToList();
if (chapters.Count == 0)
{
List<Job> retrieveChapterJobs = context.Jobs.Where(j => j.JobType == JobType.RetrieveChaptersJob).ToList();
if (retrieveChapterJobs.Any(j => j is RetrieveChaptersJob rcj && rcj.MangaId == MangaId))
{
Response.Headers.Add("Retry-After", $"{TrangaSettings.startNewJobTimeoutMs * retrieveChapterJobs.Count() * 2 / 1000:D}");
return StatusCode(Status503ServiceUnavailable, TrangaSettings.startNewJobTimeoutMs * retrieveChapterJobs.Count() * 2/ 1000);
}else
return NoContent();
}
Chapter? max = chapters.Max();
if (max is null)
@ -242,20 +255,31 @@ public class MangaController(PgsqlContext context) : Controller
/// <response code="204">No available chapters</response>
/// <response code="404">Manga with ID not found.</response>
/// <response code="500">Could not retrieve the maximum chapter-number</response>
/// <response code="503">Retry after timeout, updating value</response>
[HttpGet("{MangaId}/Chapter/LatestDownloaded")]
[ProducesResponseType<Chapter>(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
[ProducesResponseType<int>(Status503ServiceUnavailable, "text/plain")]
public IActionResult GetLatestChapterDownloaded(string MangaId)
{
Manga? m = context.Mangas.Find(MangaId);
if (m is null)
return NotFound();
List<Chapter> chapters = context.Chapters.Where(c => c.ParentMangaId == m.MangaId && c.Downloaded == true).ToList();
if (chapters.Count == 0)
{
List<Job> retrieveChapterJobs = context.Jobs.Where(j => j.JobType == JobType.RetrieveChaptersJob).ToList();
if (retrieveChapterJobs.Any(j => j is RetrieveChaptersJob rcj && rcj.MangaId == MangaId))
{
Response.Headers.Add("Retry-After", $"{TrangaSettings.startNewJobTimeoutMs * retrieveChapterJobs.Count() * 2 / 1000:D}");
return StatusCode(Status503ServiceUnavailable, TrangaSettings.startNewJobTimeoutMs * retrieveChapterJobs.Count() * 2 / 1000);
}else
return NoContent();
}
Chapter? max = chapters.Max();
if (max is null)

View File

@ -0,0 +1,35 @@
namespace API;
public interface IHttpRequestTimeFeature
{
DateTime RequestTime { get; }
}
public class HttpRequestTimeFeature : IHttpRequestTimeFeature
{
public DateTime RequestTime { get; }
public HttpRequestTimeFeature()
{
RequestTime = DateTime.Now;
}
}
public class RequestTimeMiddleware
{
private readonly RequestDelegate _next;
public RequestTimeMiddleware(RequestDelegate next)
{
_next = next;
}
public Task InvokeAsync(HttpContext context)
{
var httpRequestTimeFeature = new HttpRequestTimeFeature();
context.Features.Set<IHttpRequestTimeFeature>(httpRequestTimeFeature);
// Call the next delegate/middleware in the pipeline
return this._next(context);
}
}

View File

@ -95,6 +95,8 @@ app.UseSwaggerUI(options =>
app.UseHttpsRedirection();
//app.UseMiddleware<RequestTimeMiddleware>();
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<PgsqlContext>();

View File

@ -14,6 +14,7 @@ public class Chapter : IComparable<Chapter>
: this(parentManga.MangaId, url, chapterNumber, volumeNumber, title)
{
ParentManga = parentManga;
FileName = GetArchiveFilePath(parentManga.Name);
}
public Chapter(string parentMangaId, string url, string chapterNumber,
@ -25,7 +26,6 @@ public class Chapter : IComparable<Chapter>
ChapterNumber = chapterNumber;
VolumeNumber = volumeNumber;
Title = title;
FileName = GetArchiveFilePath();
}
[StringLength(64)]
@ -106,9 +106,9 @@ public class Chapter : IComparable<Chapter>
return File.Exists(path);
}
private string GetArchiveFilePath()
private string GetArchiveFilePath(string? parentMangaName = null)
{
return $"{ParentManga!.Name} - Vol.{VolumeNumber ?? 0} Ch.{ChapterNumber}{(Title is null ? "" : $" - {Title}")}.cbz";
return $"{parentMangaName ?? ParentManga?.Name ?? ""} - Vol.{VolumeNumber ?? 0} Ch.{ChapterNumber}{(Title is null ? "" : $" - {Title}")}.cbz";
}
private static int CompareChapterNumbers(string ch1, string ch2)

View File

@ -141,6 +141,8 @@ public static class Tranga
jobsByType[job.JobType].Add(job);
IEnumerable<Job> ret = new List<Job>();
if(jobsByType.ContainsKey(JobType.MoveMangaLibraryJob))
ret = ret.Concat(jobsByType[JobType.MoveMangaLibraryJob]);
if(jobsByType.ContainsKey(JobType.MoveFileOrFolderJob))
ret = ret.Concat(jobsByType[JobType.MoveFileOrFolderJob]);
if(jobsByType.ContainsKey(JobType.DownloadMangaCoverJob))