diff --git a/API/Controllers/FileLibraryController.cs b/API/Controllers/FileLibraryController.cs
index 84e52bf..bd9df1d 100644
--- a/API/Controllers/FileLibraryController.cs
+++ b/API/Controllers/FileLibraryController.cs
@@ -1,6 +1,7 @@
using API.Schema.MangaContext;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
using static Microsoft.AspNetCore.Http.StatusCodes;
// ReSharper disable InconsistentNaming
@@ -15,11 +16,14 @@ public class FileLibraryController(MangaContext context) : Controller
/// Returns all
///
///
+ /// Error during Database Operation
[HttpGet]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetFileLibraries()
+ public async Task GetFileLibraries ()
{
- return Ok(context.FileLibraries.ToArray());
+ if(await context.FileLibraries.ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return StatusCode(Status500InternalServerError);
+ return Ok(result);
}
///
@@ -31,9 +35,9 @@ public class FileLibraryController(MangaContext context) : Controller
[HttpGet("{FileLibraryId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetFileLibrary(string FileLibraryId)
+ public async Task GetFileLibrary (string FileLibraryId)
{
- if (context.FileLibraries.Find(FileLibraryId) is not { } library)
+ if(await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == FileLibraryId, HttpContext.RequestAborted) is not { } library)
return NotFound();
return Ok(library);
@@ -51,15 +55,15 @@ public class FileLibraryController(MangaContext context) : Controller
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult ChangeLibraryBasePath(string FileLibraryId, [FromBody]string newBasePath)
+ public async Task ChangeLibraryBasePath (string FileLibraryId, [FromBody]string newBasePath)
{
- if (context.FileLibraries.Find(FileLibraryId) is not { } library)
+ if(await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == FileLibraryId, HttpContext.RequestAborted) is not { } library)
return NotFound();
//TODO Path check
library.BasePath = newBasePath;
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok();
}
@@ -77,21 +81,21 @@ public class FileLibraryController(MangaContext context) : Controller
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status400BadRequest)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult ChangeLibraryName(string FileLibraryId, [FromBody] string newName)
+ public async Task ChangeLibraryName (string FileLibraryId, [FromBody] string newName)
{
- if (context.FileLibraries.Find(FileLibraryId) is not { } library)
+ if(await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == FileLibraryId, HttpContext.RequestAborted) is not { } library)
return NotFound();
//TODO Name check
library.LibraryName = newName;
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok();
}
///
- /// Creates new
+ /// Creates new
///
/// New to add
///
@@ -99,13 +103,12 @@ public class FileLibraryController(MangaContext context) : Controller
[HttpPut]
[ProducesResponseType(Status201Created)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult CreateNewLibrary([FromBody]FileLibrary library)
+ public async Task CreateNewLibrary ([FromBody]FileLibrary library)
{
-
//TODO Parameter check
context.FileLibraries.Add(library);
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Created();
}
@@ -120,14 +123,14 @@ public class FileLibraryController(MangaContext context) : Controller
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult DeleteLocalLibrary(string FileLibraryId)
+ public async Task DeleteLocalLibrary (string FileLibraryId)
{
- if (context.FileLibraries.Find(FileLibraryId) is not { } library)
+ if(await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == FileLibraryId, HttpContext.RequestAborted) is not { } library)
return NotFound();
context.FileLibraries.Remove(library);
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok();
}
diff --git a/API/Controllers/LibraryConnectorController.cs b/API/Controllers/LibraryConnectorController.cs
index d1f934c..f2865fa 100644
--- a/API/Controllers/LibraryConnectorController.cs
+++ b/API/Controllers/LibraryConnectorController.cs
@@ -2,6 +2,7 @@
using API.Schema.LibraryContext.LibraryConnectors;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
using static Microsoft.AspNetCore.Http.StatusCodes;
// ReSharper disable InconsistentNaming
@@ -16,11 +17,13 @@ public class LibraryConnectorController(LibraryContext context) : Controller
/// Gets all configured
///
///
+ /// Error during Database Operation
[HttpGet]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetAllConnectors()
+ public async Task GetAllConnectors ()
{
- LibraryConnector[] connectors = context.LibraryConnectors.ToArray();
+ if (await context.LibraryConnectors.ToArrayAsync(HttpContext.RequestAborted) is not { } connectors)
+ return StatusCode(Status500InternalServerError);
return Ok(connectors);
}
@@ -34,9 +37,9 @@ public class LibraryConnectorController(LibraryContext context) : Controller
[HttpGet("{LibraryConnectorId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetConnector(string LibraryConnectorId)
+ public async Task GetConnector (string LibraryConnectorId)
{
- if (context.LibraryConnectors.Find(LibraryConnectorId) is not { } connector)
+ if (await context.LibraryConnectors.FirstOrDefaultAsync(l => l.Key == LibraryConnectorId) is not { } connector)
return NotFound();
return Ok(connector);
@@ -51,12 +54,12 @@ public class LibraryConnectorController(LibraryContext context) : Controller
[HttpPut]
[ProducesResponseType(Status201Created)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult CreateConnector([FromBody]LibraryConnector libraryConnector)
+ public async Task CreateConnector ([FromBody]LibraryConnector libraryConnector)
{
context.LibraryConnectors.Add(libraryConnector);
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Created();
}
@@ -66,20 +69,20 @@ public class LibraryConnectorController(LibraryContext context) : Controller
///
/// ToFileLibrary-Connector-ID
///
- /// with < not found.
+ /// with not found.
/// Error during Database Operation
[HttpDelete("{LibraryConnectorId}")]
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult DeleteConnector(string LibraryConnectorId)
+ public async Task DeleteConnector (string LibraryConnectorId)
{
- if (context.LibraryConnectors.Find(LibraryConnectorId) is not { } connector)
+ if (await context.LibraryConnectors.FirstOrDefaultAsync(l => l.Key == LibraryConnectorId) is not { } connector)
return NotFound();
context.LibraryConnectors.Remove(connector);
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok();
}
diff --git a/API/Controllers/MaintenanceController.cs b/API/Controllers/MaintenanceController.cs
index 844bb6d..caab816 100644
--- a/API/Controllers/MaintenanceController.cs
+++ b/API/Controllers/MaintenanceController.cs
@@ -21,15 +21,17 @@ public class MaintenanceController(MangaContext mangaContext) : Controller
[HttpPost("CleanupNoDownloadManga")]
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult CleanupNoDownloadManga()
+ public async Task CleanupNoDownloadManga()
{
- Manga[] noDownloads = mangaContext.Mangas
- .Include(m => m.MangaConnectorIds)
- .Where(m => !m.MangaConnectorIds.Any(id => id.UseForDownload))
- .ToArray();
+ if (await mangaContext.Mangas
+ .Include(m => m.MangaConnectorIds)
+ .Where(m => !m.MangaConnectorIds.Any(id => id.UseForDownload))
+ .ToArrayAsync(HttpContext.RequestAborted) is not { } noDownloads)
+ return StatusCode(Status500InternalServerError);
+
mangaContext.Mangas.RemoveRange(noDownloads);
- if(mangaContext.Sync() is { success: false } result)
+ if(await mangaContext.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok();
}
diff --git a/API/Controllers/MangaConnectorController.cs b/API/Controllers/MangaConnectorController.cs
index 23d4a7b..b04a0f6 100644
--- a/API/Controllers/MangaConnectorController.cs
+++ b/API/Controllers/MangaConnectorController.cs
@@ -75,14 +75,14 @@ public class MangaConnectorController(MangaContext context) : Controller
[ProducesResponseType(Status202Accepted)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult SetEnabled(string MangaConnectorName, bool Enabled)
+ public async Task SetEnabled(string MangaConnectorName, bool Enabled)
{
if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals(MangaConnectorName, StringComparison.InvariantCultureIgnoreCase)) is not { } connector)
return NotFound();
connector.Enabled = Enabled;
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Accepted();
}
diff --git a/API/Controllers/MangaController.cs b/API/Controllers/MangaController.cs
index 1082adb..5f0d222 100644
--- a/API/Controllers/MangaController.cs
+++ b/API/Controllers/MangaController.cs
@@ -25,49 +25,65 @@ public class MangaController(MangaContext context) : Controller
/// Returns all cached
///
///
+ /// Error during Database Operation
[HttpGet]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetAllManga()
+ public async Task GetAllManga ()
{
- return Ok(context.Mangas.ToArray());
+ if(await context.Mangas.ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return StatusCode(Status500InternalServerError);
+
+ return Ok(result);
}
///
/// Returns all cached .Keys
///
/// Keys/IDs
+ /// Error during Database Operation
[HttpGet("Keys")]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetAllMangaKeys()
+ public async Task GetAllMangaKeys ()
{
- return Ok(context.Mangas.Select(m => m.Key).ToArray());
+ if(await context.Mangas.Select(m => m.Key).ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return StatusCode(Status500InternalServerError);
+
+ return Ok(result);
}
///
/// Returns all that are being downloaded from at least one
///
///
+ /// Error during Database Operation
[HttpGet("Downloading")]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetMangaDownloading()
+ public async Task GetMangaDownloading ()
{
- Manga[] ret = context.MangaIncludeAll()
- .Where(m => m.MangaConnectorIds.Any(id => id.UseForDownload))
- .ToArray();
- return Ok(ret);
+ if(await context.MangaIncludeAll()
+ .Where(m => m.MangaConnectorIds.Any(id => id.UseForDownload))
+ .ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return StatusCode(Status500InternalServerError);
+
+ return Ok(result);
}
///
/// Returns all cached with
///
- /// Array of <.Key
+ /// Array of .Key
///
+ /// Error during Database Operation
[HttpPost("WithIDs")]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetManga([FromBody]string[] MangaIds)
+ public async Task GetManga ([FromBody]string[] MangaIds)
{
- Manga[] ret = context.MangaIncludeAll().Where(m => MangaIds.Contains(m.Key)).ToArray();
- return Ok(ret);
+ if(await context.MangaIncludeAll()
+ .Where(m => MangaIds.Contains(m.Key))
+ .ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return StatusCode(Status500InternalServerError);
+
+ return Ok(result);
}
///
@@ -79,10 +95,11 @@ public class MangaController(MangaContext context) : Controller
[HttpGet("{MangaId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetManga(string MangaId)
+ public async Task GetManga (string MangaId)
{
- if (context.MangaIncludeAll().FirstOrDefault(m => m.Key == MangaId) is not { } manga)
+ if (await context.MangaIncludeAll().FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
+
return Ok(manga);
}
@@ -97,14 +114,14 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult DeleteManga(string MangaId)
+ public async Task DeleteManga (string MangaId)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
context.Mangas.Remove(manga);
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok();
}
@@ -120,21 +137,20 @@ public class MangaController(MangaContext context) : Controller
[HttpPatch("{MangaIdFrom}/MergeInto/{MangaIdInto}")]
[ProducesResponseType(Status200OK,"image/jpeg")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult MergeIntoManga(string MangaIdFrom, string MangaIdInto)
+ public async Task MergeIntoManga (string MangaIdFrom, string MangaIdInto)
{
- if (context.Mangas.Find(MangaIdFrom) is not { } from)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaIdFrom, HttpContext.RequestAborted) is not { } from)
return NotFound(nameof(MangaIdFrom));
- if (context.Mangas.Find(MangaIdInto) is not { } into)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaIdInto, HttpContext.RequestAborted) is not { } into)
return NotFound(nameof(MangaIdInto));
-
foreach (CollectionEntry collectionEntry in context.Entry(from).Collections)
- collectionEntry.Load();
- context.Entry(from).Navigation(nameof(Manga.Library)).Load();
+ await collectionEntry.LoadAsync(HttpContext.RequestAborted);
+ await context.Entry(from).Navigation(nameof(Manga.Library)).LoadAsync(HttpContext.RequestAborted);
foreach (CollectionEntry collectionEntry in context.Entry(into).Collections)
- collectionEntry.Load();
- context.Entry(into).Navigation(nameof(Manga.Library)).Load();
+ await collectionEntry.LoadAsync(HttpContext.RequestAborted);
+ await context.Entry(into).Navigation(nameof(Manga.Library)).LoadAsync(HttpContext.RequestAborted);
BaseWorker[] newJobs = into.MergeFrom(from, context);
Tranga.AddWorkers(newJobs);
@@ -159,9 +175,9 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status400BadRequest)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status503ServiceUnavailable, "text/plain")]
- public IActionResult GetCover(string MangaId, [FromQuery]int? width, [FromQuery]int? height)
+ public async Task GetCover (string MangaId, [FromQuery]int? width, [FromQuery]int? height)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
if (!System.IO.File.Exists(manga.CoverFileNameInCache))
@@ -175,7 +191,7 @@ public class MangaController(MangaContext context) : Controller
return NoContent();
}
- Image image = Image.Load(manga.CoverFileNameInCache);
+ Image image = await Image.LoadAsync(manga.CoverFileNameInCache, HttpContext.RequestAborted);
if (width is { } w && height is { } h)
{
@@ -189,7 +205,7 @@ public class MangaController(MangaContext context) : Controller
}
using MemoryStream ms = new();
- image.Save(ms, new JpegEncoder(){Quality = 100});
+ await image.SaveAsync(ms, new JpegEncoder(){Quality = 100}, HttpContext.RequestAborted);
DateTime lastModified = new FileInfo(manga.CoverFileNameInCache).LastWriteTime;
HttpContext.Response.Headers.CacheControl = "public";
return File(ms.GetBuffer(), "image/jpeg", new DateTimeOffset(lastModified), EntityTagHeaderValue.Parse($"\"{lastModified.Ticks}\""));
@@ -204,12 +220,12 @@ public class MangaController(MangaContext context) : Controller
[HttpGet("{MangaId}/Chapters")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetChapters(string MangaId)
+ public async Task GetChapters (string MangaId)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
- context.Entry(manga).Collection(m => m.Chapters).Load();
+ await context.Entry(manga).Collection(m => m.Chapters).LoadAsync();
Chapter[] chapters = manga.Chapters.ToArray();
return Ok(chapters);
@@ -226,12 +242,12 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetChaptersDownloaded(string MangaId)
+ public async Task GetChaptersDownloaded (string MangaId)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
- context.Entry(manga).Collection(m => m.Chapters).Load();
+ await context.Entry(manga).Collection(m => m.Chapters).LoadAsync();
List chapters = manga.Chapters.Where(c => c.Downloaded).ToList();
if (chapters.Count == 0)
@@ -251,12 +267,12 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status204NoContent)]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetChaptersNotDownloaded(string MangaId)
+ public async Task GetChaptersNotDownloaded (string MangaId)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
- context.Entry(manga).Collection(m => m.Chapters).Load();
+ await context.Entry(manga).Collection(m => m.Chapters).LoadAsync(HttpContext.RequestAborted);
List chapters = manga.Chapters.Where(c => c.Downloaded == false).ToList();
if (chapters.Count == 0)
@@ -280,12 +296,12 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status404NotFound, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
[ProducesResponseType(Status503ServiceUnavailable, "text/plain")]
- public IActionResult GetLatestChapter(string MangaId)
+ public async Task GetLatestChapter (string MangaId)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
- context.Entry(manga).Collection(m => m.Chapters).Load();
+ await context.Entry(manga).Collection(m => m.Chapters).LoadAsync(HttpContext.RequestAborted);
List chapters = manga.Chapters.ToList();
if (chapters.Count == 0)
@@ -303,8 +319,8 @@ public class MangaController(MangaContext context) : Controller
return StatusCode(Status500InternalServerError, "Max chapter could not be found");
foreach (CollectionEntry collectionEntry in context.Entry(max).Collections)
- collectionEntry.Load();
- context.Entry(max).Navigation(nameof(Chapter.ParentManga)).Load();
+ await collectionEntry.LoadAsync(HttpContext.RequestAborted);
+ await context.Entry(max).Navigation(nameof(Chapter.ParentManga)).LoadAsync(HttpContext.RequestAborted);
return Ok(max);
}
@@ -324,12 +340,12 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status412PreconditionFailed, "text/plain")]
[ProducesResponseType(Status503ServiceUnavailable, "text/plain")]
- public IActionResult GetLatestChapterDownloaded(string MangaId)
+ public async Task GetLatestChapterDownloaded (string MangaId)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
- context.Entry(manga).Collection(m => m.Chapters).Load();
+ await context.Entry(manga).Collection(m => m.Chapters).LoadAsync(HttpContext.RequestAborted);
List chapters = manga.Chapters.ToList();
if (chapters.Count == 0)
@@ -347,8 +363,8 @@ public class MangaController(MangaContext context) : Controller
return StatusCode(Status412PreconditionFailed, "Max chapter could not be found");
foreach (CollectionEntry collectionEntry in context.Entry(max).Collections)
- collectionEntry.Load();
- context.Entry(max).Navigation(nameof(Chapter.ParentManga)).Load();
+ await collectionEntry.LoadAsync(HttpContext.RequestAborted);
+ await context.Entry(max).Navigation(nameof(Chapter.ParentManga)).LoadAsync(HttpContext.RequestAborted);
return Ok(max);
}
@@ -365,13 +381,13 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status202Accepted)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult IgnoreChaptersBefore(string MangaId, [FromBody]float chapterThreshold)
+ public async Task IgnoreChaptersBefore (string MangaId, [FromBody]float chapterThreshold)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
- return NotFound();
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return NotFound(nameof(MangaId));
manga.IgnoreChaptersBefore = chapterThreshold;
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Accepted();
@@ -387,16 +403,16 @@ public class MangaController(MangaContext context) : Controller
[HttpPost("{MangaId}/ChangeLibrary/{LibraryId}")]
[ProducesResponseType(Status202Accepted)]
[ProducesResponseType(Status404NotFound)]
- public IActionResult ChangeLibrary(string MangaId, string LibraryId)
+ public async Task ChangeLibrary (string MangaId, string LibraryId)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
- if(context.FileLibraries.Find(LibraryId) is not { } library)
+ if (await context.FileLibraries.FirstOrDefaultAsync(l => l.Key == LibraryId, HttpContext.RequestAborted) is not { } library)
return NotFound(nameof(LibraryId));
foreach (CollectionEntry collectionEntry in context.Entry(manga).Collections)
- collectionEntry.Load();
- context.Entry(manga).Navigation(nameof(Manga.Library)).Load();
+ await collectionEntry.LoadAsync(HttpContext.RequestAborted);
+ await context.Entry(manga).Navigation(nameof(Manga.Library)).LoadAsync(HttpContext.RequestAborted);
MoveMangaLibraryWorker moveLibrary = new(manga, library);
@@ -422,11 +438,11 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status412PreconditionFailed, "text/plain")]
[ProducesResponseType(Status428PreconditionRequired, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult MarkAsRequested(string MangaId, string MangaConnectorName, bool IsRequested)
+ public async Task MarkAsRequested (string MangaId, string MangaConnectorName, bool IsRequested)
{
- if (context.Mangas.Find(MangaId) is null)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } _)
return NotFound(nameof(MangaId));
- if(!Tranga.TryGetMangaConnector(MangaConnectorName, out MangaConnector? mangaConnector))
+ if(!Tranga.TryGetMangaConnector(MangaConnectorName, out MangaConnector? _))
return NotFound(nameof(MangaConnectorName));
if (context.MangaConnectorToManga
@@ -440,7 +456,7 @@ public class MangaController(MangaContext context) : Controller
}
mcId.UseForDownload = IsRequested;
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
@@ -463,9 +479,9 @@ public class MangaController(MangaContext context) : Controller
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status406NotAcceptable)]
- public IActionResult SearchOnDifferentConnector(string MangaId, string MangaConnectorName)
+ public async Task SearchOnDifferentConnector (string MangaId, string MangaConnectorName)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
return NotFound(nameof(MangaId));
return new SearchController(context).SearchManga(MangaConnectorName, manga.Name);
@@ -479,10 +495,10 @@ public class MangaController(MangaContext context) : Controller
/// with
[HttpGet("WithAuthorId/{AuthorId}")]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetMangaWithAuthorIds(string AuthorId)
+ public async Task GetMangaWithAuthorIds (string AuthorId)
{
- if (context.Authors.Find(AuthorId) is not { } author)
- return NotFound();
+ if (await context.Authors.FirstOrDefaultAsync(a => a.Key == AuthorId, HttpContext.RequestAborted) is not { } author)
+ return NotFound(nameof(AuthorId));
return Ok(context.Mangas.Where(m => m.Authors.Contains(author)));
}
@@ -495,10 +511,10 @@ public class MangaController(MangaContext context) : Controller
/// not found
[HttpGet("WithTag/{Tag}")]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetMangasWithTag(string Tag)
+ public async Task GetMangasWithTag (string Tag)
{
- if (context.Tags.Find(Tag) is not { } tag)
- return NotFound();
+ if (await context.Tags.FirstOrDefaultAsync(t => t.Tag == Tag, HttpContext.RequestAborted) is not { } tag)
+ return NotFound(nameof(Tag));
return Ok(context.Mangas.Where(m => m.MangaTags.Contains(tag)));
}
diff --git a/API/Controllers/MetadataFetcherController.cs b/API/Controllers/MetadataFetcherController.cs
index 6950a3c..c215b7a 100644
--- a/API/Controllers/MetadataFetcherController.cs
+++ b/API/Controllers/MetadataFetcherController.cs
@@ -3,6 +3,7 @@ using API.Schema.MangaContext.MetadataFetchers;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.EntityFrameworkCore;
using static Microsoft.AspNetCore.Http.StatusCodes;
// ReSharper disable InconsistentNaming
@@ -19,7 +20,7 @@ public class MetadataFetcherController(MangaContext context) : Controller
/// Names of (Metadata-Sites)
[HttpGet]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetConnectors()
+ public IActionResult GetConnectors ()
{
return Ok(Tranga.MetadataFetchers.Select(m => m.Name).ToArray());
}
@@ -28,11 +29,15 @@ public class MetadataFetcherController(MangaContext context) : Controller
/// Returns all
///
///
+ /// Error during Database Operation
[HttpGet("Links")]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetLinkedEntries()
+ public async Task GetLinkedEntries ()
{
- return Ok(context.MetadataEntries.ToArray());
+ if (await context.MetadataEntries.ToArrayAsync() is not { } result)
+ return StatusCode(Status500InternalServerError);
+
+ return Ok(result);
}
///
@@ -48,10 +53,10 @@ public class MetadataFetcherController(MangaContext context) : Controller
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status400BadRequest)]
[ProducesResponseType(Status404NotFound)]
- public IActionResult SearchMangaMetadata(string MangaId, string MetadataFetcherName, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)]string? searchTerm = null)
+ public async Task SearchMangaMetadata(string MangaId, string MetadataFetcherName, [FromBody (EmptyBodyBehavior = EmptyBodyBehavior.Allow)]string? searchTerm = null)
{
- if(context.Mangas.Find(MangaId) is not { } manga)
- return NotFound();
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return NotFound(nameof(MangaId));
if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is not { } fetcher)
return BadRequest();
@@ -74,18 +79,18 @@ public class MetadataFetcherController(MangaContext context) : Controller
[ProducesResponseType(Status400BadRequest)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult LinkMangaMetadata(string MangaId, string MetadataFetcherName, [FromBody]string Identifier)
+ public async Task LinkMangaMetadata (string MangaId, string MetadataFetcherName, [FromBody]string Identifier)
{
- if(context.Mangas.Find(MangaId) is not { } manga)
- return NotFound();
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return NotFound(nameof(MangaId));
if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is not { } fetcher)
return BadRequest();
MetadataEntry entry = fetcher.CreateMetadataEntry(manga, Identifier);
context.MetadataEntries.Add(entry);
- if(context.Sync() is { } errorMessage)
- return StatusCode(Status500InternalServerError, errorMessage);
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
+ return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok(entry);
}
@@ -103,10 +108,10 @@ public class MetadataFetcherController(MangaContext context) : Controller
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status412PreconditionFailed, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult UnlinkMangaMetadata(string MangaId, string MetadataFetcherName)
+ public async Task UnlinkMangaMetadata (string MangaId, string MetadataFetcherName)
{
- if(context.Mangas.Find(MangaId) is null)
- return NotFound();
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } _)
+ return NotFound(nameof(MangaId));
if(Tranga.MetadataFetchers.FirstOrDefault(f => f.Name == MetadataFetcherName) is null)
return BadRequest();
if(context.MetadataEntries.FirstOrDefault(e => e.MangaId == MangaId && e.MetadataFetcherName == MetadataFetcherName) is not { } entry)
@@ -114,7 +119,7 @@ public class MetadataFetcherController(MangaContext context) : Controller
context.Remove(entry);
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok();
}
diff --git a/API/Controllers/NotificationConnectorController.cs b/API/Controllers/NotificationConnectorController.cs
index 70f74ef..95a98c6 100644
--- a/API/Controllers/NotificationConnectorController.cs
+++ b/API/Controllers/NotificationConnectorController.cs
@@ -4,6 +4,7 @@ using API.Schema.NotificationsContext;
using API.Schema.NotificationsContext.NotificationConnectors;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
using static Microsoft.AspNetCore.Http.StatusCodes;
// ReSharper disable InconsistentNaming
@@ -19,12 +20,15 @@ public class NotificationConnectorController(NotificationsContext context) : Con
/// Gets all configured
///
///
+ /// Error during Database Operation
[HttpGet]
[ProducesResponseType(Status200OK, "application/json")]
- public IActionResult GetAllConnectors()
+ public async Task GetAllConnectors ()
{
+ if(await context.NotificationConnectors.ToArrayAsync(HttpContext.RequestAborted) is not { } result)
+ return StatusCode(Status500InternalServerError);
- return Ok(context.NotificationConnectors.ToArray());
+ return Ok(result);
}
///
@@ -36,10 +40,10 @@ public class NotificationConnectorController(NotificationsContext context) : Con
[HttpGet("{Name}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetConnector(string Name)
+ public async Task GetConnector (string Name)
{
- if(context.NotificationConnectors.Find(Name) is not { } connector)
- return NotFound();
+ if (await context.NotificationConnectors.FirstOrDefaultAsync(c => c.Name == Name, HttpContext.RequestAborted) is not { } connector)
+ return NotFound(nameof(Name));
return Ok(connector);
}
@@ -53,12 +57,12 @@ public class NotificationConnectorController(NotificationsContext context) : Con
[HttpPut]
[ProducesResponseType(Status200OK, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult CreateConnector([FromBody]NotificationConnector notificationConnector)
+ public async Task CreateConnector ([FromBody]NotificationConnector notificationConnector)
{
context.NotificationConnectors.Add(notificationConnector);
context.Notifications.Add(new ("Added new Notification Connector!", notificationConnector.Name, NotificationUrgency.High));
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok(notificationConnector.Name);
}
@@ -72,7 +76,7 @@ public class NotificationConnectorController(NotificationsContext context) : Con
[HttpPut("Gotify")]
[ProducesResponseType(Status200OK, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult CreateGotifyConnector([FromBody]GotifyRecord gotifyData)
+ public async Task CreateGotifyConnector ([FromBody]GotifyRecord gotifyData)
{
//TODO Validate Data
@@ -81,7 +85,7 @@ public class NotificationConnectorController(NotificationsContext context) : Con
new Dictionary() { { "X-Gotify-Key", gotifyData.AppToken } },
"POST",
$"{{\"message\": \"%text\", \"title\": \"%title\", \"Priority\": {gotifyData.Priority}}}");
- return CreateConnector(gotifyConnector);
+ return await CreateConnector(gotifyConnector);
}
///
@@ -93,7 +97,7 @@ public class NotificationConnectorController(NotificationsContext context) : Con
[HttpPut("Ntfy")]
[ProducesResponseType(Status200OK, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult CreateNtfyConnector([FromBody]NtfyRecord ntfyRecord)
+ public async Task CreateNtfyConnector ([FromBody]NtfyRecord ntfyRecord)
{
//TODO Validate Data
@@ -108,7 +112,7 @@ public class NotificationConnectorController(NotificationsContext context) : Con
},
"POST",
$"{{\"message\": \"%text\", \"title\": \"%title\", \"Priority\": {ntfyRecord.Priority} \"Topic\": \"{ntfyRecord.Topic}\"}}");
- return CreateConnector(ntfyConnector);
+ return await CreateConnector(ntfyConnector);
}
///
@@ -120,7 +124,7 @@ public class NotificationConnectorController(NotificationsContext context) : Con
[HttpPut("Pushover")]
[ProducesResponseType(Status200OK, "text/plain")]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult CreatePushoverConnector([FromBody]PushoverRecord pushoverRecord)
+ public async Task CreatePushoverConnector ([FromBody]PushoverRecord pushoverRecord)
{
//TODO Validate Data
@@ -129,7 +133,7 @@ public class NotificationConnectorController(NotificationsContext context) : Con
new Dictionary(),
"POST",
$"{{\"token\": \"{pushoverRecord.AppToken}\", \"user\": \"{pushoverRecord.User}\", \"message:\":\"%text\", \"%title\" }}");
- return CreateConnector(pushoverConnector);
+ return await CreateConnector(pushoverConnector);
}
///
@@ -143,14 +147,14 @@ public class NotificationConnectorController(NotificationsContext context) : Con
[ProducesResponseType(Status200OK)]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError, "text/plain")]
- public IActionResult DeleteConnector(string Name)
+ public async Task DeleteConnector (string Name)
{
- if(context.NotificationConnectors.Find(Name) is not { } connector)
- return NotFound();
+ if (await context.NotificationConnectors.FirstOrDefaultAsync(c => c.Name == Name, HttpContext.RequestAborted) is not { } connector)
+ return NotFound(nameof(Name));
context.NotificationConnectors.Remove(connector);
- if(context.Sync() is { success: false } result)
+ if(await context.Sync(HttpContext.RequestAborted) is { success: false } result)
return StatusCode(Status500InternalServerError, result.exceptionMessage);
return Ok();
}
diff --git a/API/Controllers/QueryController.cs b/API/Controllers/QueryController.cs
index 27b1af1..0318b5d 100644
--- a/API/Controllers/QueryController.cs
+++ b/API/Controllers/QueryController.cs
@@ -1,7 +1,7 @@
-using API.MangaConnectors;
-using API.Schema.MangaContext;
+using API.Schema.MangaContext;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
using Soenneker.Utils.String.NeedlemanWunsch;
using static Microsoft.AspNetCore.Http.StatusCodes;
// ReSharper disable InconsistentNaming
@@ -22,10 +22,10 @@ public class QueryController(MangaContext context) : Controller
[HttpGet("Author/{AuthorId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetAuthor(string AuthorId)
+ public async Task GetAuthor (string AuthorId)
{
- if (context.Authors.Find(AuthorId) is not { } author)
- return NotFound();
+ if (await context.Authors.FirstOrDefaultAsync(a => a.Key == AuthorId, HttpContext.RequestAborted) is not { } author)
+ return NotFound(nameof(AuthorId));
return Ok(author);
}
@@ -39,10 +39,10 @@ public class QueryController(MangaContext context) : Controller
[HttpGet("Chapter/{ChapterId}")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetChapter(string ChapterId)
+ public async Task GetChapter (string ChapterId)
{
- if (context.Chapters.Find(ChapterId) is not { } chapter)
- return NotFound();
+ if (await context.Chapters.FirstOrDefaultAsync(c => c.Key == ChapterId, HttpContext.RequestAborted) is not { } chapter)
+ return NotFound(nameof(ChapterId));
return Ok(chapter);
}
@@ -56,10 +56,10 @@ public class QueryController(MangaContext context) : Controller
[HttpGet("Manga/MangaConnectorId/{MangaConnectorIdId}")]
[ProducesResponseType>(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetMangaMangaConnectorId(string MangaConnectorIdId)
+ public async Task GetMangaMangaConnectorId (string MangaConnectorIdId)
{
- if(context.MangaConnectorToManga.Find(MangaConnectorIdId) is not { } mcIdManga)
- return NotFound();
+ if (await context.MangaConnectorToManga.FirstOrDefaultAsync(c => c.Key == MangaConnectorIdId, HttpContext.RequestAborted) is not { } mcIdManga)
+ return NotFound(nameof(MangaConnectorIdId));
return Ok(mcIdManga);
}
@@ -70,18 +70,24 @@ public class QueryController(MangaContext context) : Controller
/// Key of
///
/// with not found
+ /// Error during Database Operation
[HttpGet("Manga/{MangaId}/SimilarName")]
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetSimilarManga(string MangaId)
+ public async Task GetSimilarManga (string MangaId)
{
- if (context.Mangas.Find(MangaId) is not { } manga)
- return NotFound();
+ if (await context.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, HttpContext.RequestAborted) is not { } manga)
+ return NotFound(nameof(MangaId));
+
string name = manga.Name;
- Dictionary mangaNames = context.Mangas.Where(m => m.Key != MangaId).ToDictionary(m => m.Key, m => m.Name);
+
+ if(await context.Mangas.Where(m => m.Key != MangaId).ToDictionaryAsync(m => m.Key, m => m.Name, HttpContext.RequestAborted) is not { } mangaNames)
+ return StatusCode(Status500InternalServerError);
+
string[] similarIds = mangaNames
.Where(kv => NeedlemanWunschStringUtil.CalculateSimilarityPercentage(name, kv.Value) > 0.8)
.Select(kv => kv.Key).ToArray();
+
return Ok(similarIds);
}
@@ -94,10 +100,10 @@ public class QueryController(MangaContext context) : Controller
[HttpGet("Chapter/MangaConnectorId/{MangaConnectorIdId}")]
[ProducesResponseType>(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
- public IActionResult GetChapterMangaConnectorId(string MangaConnectorIdId)
+ public async Task GetChapterMangaConnectorId (string MangaConnectorIdId)
{
- if(context.MangaConnectorToChapter.Find(MangaConnectorIdId) is not { } mcIdChapter)
- return NotFound();
+ if (await context.MangaConnectorToManga.FirstOrDefaultAsync(c => c.Key == MangaConnectorIdId, HttpContext.RequestAborted) is not { } mcIdChapter)
+ return NotFound(nameof(MangaConnectorIdId));
return Ok(mcIdChapter);
}
diff --git a/API/Controllers/SearchController.cs b/API/Controllers/SearchController.cs
index 4f89d1a..7d38834 100644
--- a/API/Controllers/SearchController.cs
+++ b/API/Controllers/SearchController.cs
@@ -24,7 +24,7 @@ public class SearchController(MangaContext context) : Controller
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status406NotAcceptable)]
- public IActionResult SearchManga(string MangaConnectorName, string Query)
+ public IActionResult SearchManga (string MangaConnectorName, string Query)
{
if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals(MangaConnectorName, StringComparison.InvariantCultureIgnoreCase)) is not { } connector)
return NotFound();
@@ -35,7 +35,7 @@ public class SearchController(MangaContext context) : Controller
List retMangas = new();
foreach ((Manga manga, MangaConnectorId mcId) manga in mangas)
{
- if(Tranga.AddMangaToContext(manga, context, out Manga? add))
+ if(Tranga.AddMangaToContext(manga, context, out Manga? add, HttpContext.RequestAborted))
retMangas.Add(add);
}
@@ -54,7 +54,7 @@ public class SearchController(MangaContext context) : Controller
[ProducesResponseType(Status200OK, "application/json")]
[ProducesResponseType(Status404NotFound)]
[ProducesResponseType(Status500InternalServerError)]
- public IActionResult GetMangaFromUrl([FromBody]string url)
+ public IActionResult GetMangaFromUrl ([FromBody]string url)
{
if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals("Global", StringComparison.InvariantCultureIgnoreCase)) is not { } connector)
return StatusCode(Status500InternalServerError, "Could not find Global Connector.");
@@ -62,7 +62,7 @@ public class SearchController(MangaContext context) : Controller
if(connector.GetMangaFromUrl(url) is not { } manga)
return NotFound();
- if(Tranga.AddMangaToContext(manga, context, out Manga? add) == false)
+ if(Tranga.AddMangaToContext(manga, context, out Manga? add, HttpContext.RequestAborted) == false)
return StatusCode(Status500InternalServerError);
return Ok(add);
diff --git a/API/Controllers/WorkerController.cs b/API/Controllers/WorkerController.cs
index 9c8f807..871df70 100644
--- a/API/Controllers/WorkerController.cs
+++ b/API/Controllers/WorkerController.cs
@@ -1,5 +1,4 @@
-using API.APIEndpointRecords;
-using API.Workers;
+using API.Workers;
using Asp.Versioning;
using Microsoft.AspNetCore.Mvc;
using static Microsoft.AspNetCore.Http.StatusCodes;
diff --git a/API/Program.cs b/API/Program.cs
index 4a53e16..5004004 100644
--- a/API/Program.cs
+++ b/API/Program.cs
@@ -1,6 +1,5 @@
using System.Reflection;
using API;
-using API.MangaConnectors;
using API.Schema.LibraryContext;
using API.Schema.MangaContext;
using API.Schema.NotificationsContext;
@@ -76,7 +75,7 @@ builder.Services.AddControllers().AddNewtonsoftJson(opts =>
opts.SerializerSettings.Converters.Add(new StringEnumConverter());
opts.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
-builder.Services.AddScoped(opts => LogManager.GetLogger("API"));
+builder.Services.AddScoped(_ => LogManager.GetLogger("API"));
builder.WebHost.UseUrls("http://*:6531");
@@ -112,7 +111,7 @@ using (IServiceScope scope = app.Services.CreateScope())
if (!context.FileLibraries.Any())
context.FileLibraries.Add(new FileLibrary(Tranga.Settings.DownloadLocation, "Default FileLibrary"));
- context.Sync();
+ await context.Sync(CancellationToken.None);
}
using (IServiceScope scope = app.Services.CreateScope())
@@ -124,7 +123,7 @@ using (IServiceScope scope = app.Services.CreateScope())
string[] emojis = { "(•‿•)", "(づ \u25d5‿\u25d5 )づ", "( \u02d8\u25bd\u02d8)っ\u2668", "=\uff3e\u25cf \u22cf \u25cf\uff3e=", "(ΦωΦ)", "(\u272a\u3268\u272a)", "( ノ・o・ )ノ", "(〜^\u2207^ )〜", "~(\u2267ω\u2266)~","૮ \u00b4• ﻌ \u00b4• ა", "(\u02c3ᆺ\u02c2)", "(=\ud83d\udf66 \u0f1d \ud83d\udf66=)"};
context.Notifications.Add(new Notification("Tranga Started", emojis[Random.Shared.Next(0, emojis.Length - 1)], NotificationUrgency.High));
- context.Sync();
+ await context.Sync(CancellationToken.None);
}
using (IServiceScope scope = app.Services.CreateScope())
@@ -132,7 +131,7 @@ using (IServiceScope scope = app.Services.CreateScope())
LibraryContext context = scope.ServiceProvider.GetRequiredService();
context.Database.Migrate();
- context.Sync();
+ await context.Sync(CancellationToken.None);
}
Tranga.SetServiceProvider(app.Services);
diff --git a/API/Schema/Identifiable.cs b/API/Schema/Identifiable.cs
index fe05db6..93b1980 100644
--- a/API/Schema/Identifiable.cs
+++ b/API/Schema/Identifiable.cs
@@ -6,12 +6,12 @@ namespace API.Schema;
[PrimaryKey("Key")]
public abstract class Identifiable
{
- public Identifiable()
+ protected Identifiable()
{
this.Key = TokenGen.CreateToken(this.GetType());
}
-
- public Identifiable(string key)
+
+ protected Identifiable(string key)
{
this.Key = key;
}
diff --git a/API/Schema/MangaContext/MangaContext.cs b/API/Schema/MangaContext/MangaContext.cs
index 9a1f2ca..38a0f5c 100644
--- a/API/Schema/MangaContext/MangaContext.cs
+++ b/API/Schema/MangaContext/MangaContext.cs
@@ -104,15 +104,15 @@ public class MangaContext(DbContextOptions options) : TrangaBaseCo
.OnDelete(DeleteBehavior.Cascade);
}
- public Manga? FindMangaLike(Manga other)
+ public async Task FindMangaLike(Manga other, CancellationToken token)
{
- if (MangaIncludeAll().FirstOrDefault(m => m.Key == other.Key) is { } f)
+ if (await MangaIncludeAll().FirstOrDefaultAsync(m => m.Key == other.Key, token) is { } f)
return f;
- return MangaIncludeAll()
- .FirstOrDefault(m => m.Links.Any(l => l.Key == other.Key) ||
- m.AltTitles.Any(t => other.AltTitles.Select(ot => ot.Title)
- .Any(s => s.Equals(t.Title))));
+ return await MangaIncludeAll()
+ .FirstOrDefaultAsync(m =>
+ m.Links.Any(l => l.Key == other.Key) ||
+ m.AltTitles.Any(t => other.AltTitles.Select(ot => ot.Title).Any(s => s.Equals(t.Title))), token);
}
public IIncludableQueryable>> MangaIncludeAll() => Mangas.Include(m => m.Library)
diff --git a/API/Schema/MangaContext/MetadataFetchers/MetadataFetcher.cs b/API/Schema/MangaContext/MetadataFetchers/MetadataFetcher.cs
index 37c36b8..e436795 100644
--- a/API/Schema/MangaContext/MetadataFetchers/MetadataFetcher.cs
+++ b/API/Schema/MangaContext/MetadataFetchers/MetadataFetcher.cs
@@ -31,5 +31,5 @@ public abstract class MetadataFetcher
///
/// Updates the Manga linked in the MetadataEntry
///
- public abstract void UpdateMetadata(MetadataEntry metadataEntry, MangaContext dbContext);
+ public abstract Task UpdateMetadata(MetadataEntry metadataEntry, MangaContext dbContext, CancellationToken token);
}
\ No newline at end of file
diff --git a/API/Schema/MangaContext/MetadataFetchers/MyAnimeList.cs b/API/Schema/MangaContext/MetadataFetchers/MyAnimeList.cs
index 6748868..f4fd305 100644
--- a/API/Schema/MangaContext/MetadataFetchers/MyAnimeList.cs
+++ b/API/Schema/MangaContext/MetadataFetchers/MyAnimeList.cs
@@ -43,21 +43,25 @@ public class MyAnimeList : MetadataFetcher
///
///
///
+ ///
///
///
- public override void UpdateMetadata(MetadataEntry metadataEntry, MangaContext dbContext)
+ public override async Task UpdateMetadata(MetadataEntry metadataEntry, MangaContext dbContext, CancellationToken token)
{
- Manga dbManga = dbContext.Mangas.Find(metadataEntry.MangaId)!;
+ if (await dbContext.Mangas.FirstOrDefaultAsync(m => m.Key == metadataEntry.MangaId, token) is not { } dbManga)
+ throw new DbUpdateException("Manga not found");
foreach (CollectionEntry collectionEntry in dbContext.Entry(dbManga).Collections)
- collectionEntry.Load();
- dbContext.Entry(dbManga).Navigation(nameof(Manga.Library)).Load();
+ await collectionEntry.LoadAsync(token);
+ await dbContext.Entry(dbManga).Navigation(nameof(Manga.Library)).LoadAsync(token);
MangaFull resultData;
try
{
long id = long.Parse(metadataEntry.Identifier);
- resultData = Jikan.GetMangaFullDataAsync(id).Result.Data;
+ if(await Jikan.GetMangaFullDataAsync(id, token) is not { } response)
+ throw new DbUpdateException("Manga Data not found");
+ resultData = response.Data;
}
catch (Exception)
{
@@ -71,7 +75,7 @@ public class MyAnimeList : MetadataFetcher
dbManga.Authors.Clear();
dbManga.Authors = resultData.Authors.Select(a => new Author(a.Name)).ToList();
- dbContext.Sync();
+ await dbContext.Sync(token);
}
}
\ No newline at end of file
diff --git a/API/Schema/TrangaBaseContext.cs b/API/Schema/TrangaBaseContext.cs
index 58f6239..c5c6261 100644
--- a/API/Schema/TrangaBaseContext.cs
+++ b/API/Schema/TrangaBaseContext.cs
@@ -22,11 +22,11 @@ public abstract class TrangaBaseContext : DbContext where T : DbContext
}, Array.Empty(), LogLevel.Warning, DbContextLoggerOptions.Level | DbContextLoggerOptions.Category | DbContextLoggerOptions.UtcTime);
}
- internal (bool success, string? exceptionMessage) Sync()
+ internal async Task<(bool success, string? exceptionMessage)> Sync(CancellationToken token)
{
try
{
- this.SaveChanges();
+ await this.SaveChangesAsync(token);
return (true, null);
}
catch (Exception e)
diff --git a/API/Tranga.cs b/API/Tranga.cs
index a2500d7..71e63c2 100644
--- a/API/Tranga.cs
+++ b/API/Tranga.cs
@@ -158,12 +158,13 @@ public static class Tranga
RunningWorkers.Remove(worker, out _);
}
- internal static bool AddMangaToContext((Manga, MangaConnectorId) addManga, MangaContext context, [NotNullWhen(true)]out Manga? manga) => AddMangaToContext(addManga.Item1, addManga.Item2, context, out manga);
+ internal static bool AddMangaToContext((Manga, MangaConnectorId) addManga, MangaContext context, [NotNullWhen(true)]out Manga? manga, CancellationToken token) =>
+ AddMangaToContext(addManga.Item1, addManga.Item2, context, out manga, token);
- internal static bool AddMangaToContext(Manga addManga, MangaConnectorId addMcId, MangaContext context, [NotNullWhen(true)]out Manga? manga)
+ internal static bool AddMangaToContext(Manga addManga, MangaConnectorId addMcId, MangaContext context, [NotNullWhen(true)]out Manga? manga, CancellationToken token)
{
context.ChangeTracker.Clear();
- manga = context.FindMangaLike(addManga);
+ manga = context.FindMangaLike(addManga, token).Result;
if (manga is not null)
{
foreach (MangaConnectorId mcId in addManga.MangaConnectorIds)
@@ -198,7 +199,7 @@ public static class Tranga
context.Mangas.Add(manga);
}
- if (context.Sync() is { success: false })
+ if (context.Sync(token).Result is { success: false })
return false;
DownloadCoverFromMangaconnectorWorker downloadCoverWorker = new (addMcId);
@@ -207,10 +208,10 @@ public static class Tranga
return true;
}
- internal static bool AddChapterToContext((Chapter, MangaConnectorId) addChapter, MangaContext context,
- [NotNullWhen(true)] out Chapter? chapter) => AddChapterToContext(addChapter.Item1, addChapter.Item2, context, out chapter);
+ internal static bool AddChapterToContext((Chapter, MangaConnectorId) addChapter, MangaContext context, [NotNullWhen(true)] out Chapter? chapter, CancellationToken token) =>
+ AddChapterToContext(addChapter.Item1, addChapter.Item2, context, out chapter, token);
- internal static bool AddChapterToContext(Chapter addChapter, MangaConnectorId addChId, MangaContext context, [NotNullWhen(true)] out Chapter? chapter)
+ internal static bool AddChapterToContext(Chapter addChapter, MangaConnectorId addChId, MangaContext context, [NotNullWhen(true)] out Chapter? chapter, CancellationToken token)
{
chapter = context.Chapters.Where(ch => ch.Key == addChapter.Key)
.Include(ch => ch.ParentManga)
@@ -226,7 +227,7 @@ public static class Tranga
chapter = addChapter;
}
- if (context.Sync() is { success: false })
+ if (context.Sync(token).Result is { success: false })
return false;
return true;
}
diff --git a/API/Workers/BaseWorker.cs b/API/Workers/BaseWorker.cs
index 662826a..99f8658 100644
--- a/API/Workers/BaseWorker.cs
+++ b/API/Workers/BaseWorker.cs
@@ -26,7 +26,7 @@ public abstract class BaseWorker : Identifiable
public IEnumerable MissingDependencies => DependsOn.Where(d => d.State < WorkerExecutionState.Completed);
public bool AllDependenciesFulfilled => DependsOn.All(d => d.State >= WorkerExecutionState.Completed);
internal WorkerExecutionState State { get; private set; }
- private CancellationTokenSource? CancellationTokenSource = null;
+ protected CancellationTokenSource CancellationTokenSource = new ();
protected ILog Log { get; init; }
///
@@ -36,7 +36,7 @@ public abstract class BaseWorker : Identifiable
{
Log.Debug($"Cancelled {this}");
this.State = WorkerExecutionState.Cancelled;
- CancellationTokenSource?.Cancel();
+ CancellationTokenSource.Cancel();
}
///
@@ -46,7 +46,7 @@ public abstract class BaseWorker : Identifiable
{
Log.Debug($"Failed {this}");
this.State = WorkerExecutionState.Failed;
- CancellationTokenSource?.Cancel();
+ CancellationTokenSource.Cancel();
}
public BaseWorker(IEnumerable? dependsOn = null)
@@ -89,10 +89,9 @@ public abstract class BaseWorker : Identifiable
// Run the actual work
Log.Info($"Running {this}");
DateTime startTime = DateTime.UtcNow;
- Task task = new (DoWorkInternal, CancellationTokenSource.Token);
+ Task task = DoWorkInternal();
task.GetAwaiter().OnCompleted(Finish(startTime, callback));
this.State = WorkerExecutionState.Running;
- task.Start();
return task;
}
@@ -106,12 +105,12 @@ public abstract class BaseWorker : Identifiable
callback?.Invoke();
};
- protected abstract BaseWorker[] DoWorkInternal();
+ protected abstract Task DoWorkInternal();
private BaseWorker[] WaitForDependencies()
{
Log.Info($"Waiting for {MissingDependencies.Count()} Dependencies {this}:\n\t{string.Join("\n\t", MissingDependencies.Select(d => d.ToString()))}");
- while (CancellationTokenSource?.IsCancellationRequested == false && MissingDependencies.Any())
+ while (CancellationTokenSource.IsCancellationRequested == false && MissingDependencies.Any())
{
Thread.Sleep(Tranga.Settings.WorkCycleTimeoutMs);
}
diff --git a/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs b/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs
index 213f2a2..e0abf5c 100644
--- a/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs
+++ b/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs
@@ -3,6 +3,7 @@ using System.Runtime.InteropServices;
using API.MangaConnectors;
using API.MangaDownloadClients;
using API.Schema.MangaContext;
+using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
@@ -16,14 +17,14 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c
: BaseWorkerWithContext(dependsOn)
{
internal readonly string MangaConnectorIdId = chId.Key;
- protected override BaseWorker[] DoWorkInternal()
+ protected override async Task DoWorkInternal()
{
- if (DbContext.MangaConnectorToChapter.Find(MangaConnectorIdId) is not { } mangaConnectorId)
+ if(await DbContext.MangaConnectorToChapter.FirstOrDefaultAsync(c => c.Key == MangaConnectorIdId, CancellationTokenSource.Token) is not { } mangaConnectorId)
return []; //TODO Exception?
if (!Tranga.TryGetMangaConnector(mangaConnectorId.MangaConnectorName, out MangaConnector? mangaConnector))
return []; //TODO Exception?
- DbContext.Entry(mangaConnectorId).Navigation(nameof(MangaConnectorId.Obj)).Load();
+ await DbContext.Entry(mangaConnectorId).Navigation(nameof(MangaConnectorId.Obj)).LoadAsync(CancellationTokenSource.Token);
Chapter chapter = mangaConnectorId.Obj;
if (chapter.Downloaded)
{
@@ -31,8 +32,8 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c
return [];
}
- DbContext.Entry(chapter).Navigation(nameof(Chapter.ParentManga)).Load();
- DbContext.Entry(chapter.ParentManga).Navigation(nameof(Manga.Library)).Load();
+ await DbContext.Entry(chapter).Navigation(nameof(Chapter.ParentManga)).LoadAsync(CancellationTokenSource.Token);
+ await DbContext.Entry(chapter.ParentManga).Navigation(nameof(Manga.Library)).LoadAsync(CancellationTokenSource.Token);
if (chapter.ParentManga.LibraryId is null)
{
@@ -92,13 +93,13 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c
}
}
- CopyCoverFromCacheToDownloadLocation(chapter.ParentManga);
+ await CopyCoverFromCacheToDownloadLocation(chapter.ParentManga);
Log.Debug($"Creating ComicInfo.xml {chapter}");
foreach (CollectionEntry collectionEntry in DbContext.Entry(chapter.ParentManga).Collections)
- collectionEntry.Load();
- DbContext.Entry(chapter.ParentManga).Navigation(nameof(Manga.Library)).Load();
- File.WriteAllText(Path.Join(tempFolder, "ComicInfo.xml"), chapter.GetComicInfoXmlString());
+ await collectionEntry.LoadAsync(CancellationTokenSource.Token);
+ await DbContext.Entry(chapter.ParentManga).Navigation(nameof(Manga.Library)).LoadAsync(CancellationTokenSource.Token);
+ await File.WriteAllTextAsync(Path.Join(tempFolder, "ComicInfo.xml"), chapter.GetComicInfoXmlString(), CancellationTokenSource.Token);
Log.Debug($"Packaging images to archive {chapter}");
//ZIP-it and ship-it
@@ -108,7 +109,7 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c
Directory.Delete(tempFolder, true); //Cleanup
chapter.Downloaded = true;
- DbContext.Sync();
+ await DbContext.Sync(CancellationTokenSource.Token);
return [];
}
@@ -151,7 +152,7 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c
}
}
- private void CopyCoverFromCacheToDownloadLocation(Manga manga)
+ private async Task CopyCoverFromCacheToDownloadLocation(Manga manga)
{
//Check if Publication already has a Folder and cover
string publicationFolder = manga.CreatePublicationFolder();
@@ -163,7 +164,7 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c
}
//TODO MangaConnector Selection
- DbContext.Entry(manga).Collection(m => m.MangaConnectorIds).Load();
+ await DbContext.Entry(manga).Collection(m => m.MangaConnectorIds).LoadAsync(CancellationTokenSource.Token);
MangaConnectorId mangaConnectorId = manga.MangaConnectorIds.First();
if (!Tranga.TryGetMangaConnector(mangaConnectorId.MangaConnectorName, out MangaConnector? mangaConnector))
{
@@ -172,7 +173,7 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c
}
Log.Info($"Copying cover to {publicationFolder}");
- DbContext.Entry(mangaConnectorId).Navigation(nameof(MangaConnectorId.Obj)).Load();
+ await DbContext.Entry(mangaConnectorId).Navigation(nameof(MangaConnectorId.Obj)).LoadAsync(CancellationTokenSource.Token);
string? fileInCache = manga.CoverFileNameInCache ?? mangaConnector.SaveCoverImageToCache(mangaConnectorId);
if (fileInCache is null)
{
diff --git a/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs b/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs
index 194cbea..c6581b3 100644
--- a/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs
+++ b/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs
@@ -1,5 +1,6 @@
using API.MangaConnectors;
using API.Schema.MangaContext;
+using Microsoft.EntityFrameworkCore;
namespace API.Workers;
@@ -7,19 +8,19 @@ public class DownloadCoverFromMangaconnectorWorker(MangaConnectorId mcId,
: BaseWorkerWithContext(dependsOn)
{
internal readonly string MangaConnectorIdId = mcId.Key;
- protected override BaseWorker[] DoWorkInternal()
+ protected override async Task DoWorkInternal()
{
- if (DbContext.MangaConnectorToManga.Find(MangaConnectorIdId) is not { } mangaConnectorId)
+ if (await DbContext.MangaConnectorToManga.FirstOrDefaultAsync(c => c.Key == MangaConnectorIdId) is not { } mangaConnectorId)
return []; //TODO Exception?
if (!Tranga.TryGetMangaConnector(mangaConnectorId.MangaConnectorName, out MangaConnector? mangaConnector))
return []; //TODO Exception?
- DbContext.Entry(mangaConnectorId).Navigation(nameof(MangaConnectorId.Obj)).Load();
+ await DbContext.Entry(mangaConnectorId).Navigation(nameof(MangaConnectorId.Obj)).LoadAsync(CancellationTokenSource.Token);
Manga manga = mangaConnectorId.Obj;
manga.CoverFileNameInCache = mangaConnector.SaveCoverImageToCache(mangaConnectorId);
- DbContext.Sync();
+ await DbContext.Sync(CancellationTokenSource.Token);
return [];
}
diff --git a/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs b/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs
index 716aad3..64434df 100644
--- a/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs
+++ b/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs
@@ -1,5 +1,6 @@
using API.MangaConnectors;
using API.Schema.MangaContext;
+using Microsoft.EntityFrameworkCore;
namespace API.Workers;
@@ -7,16 +8,16 @@ public class RetrieveMangaChaptersFromMangaconnectorWorker(MangaConnectorId(dependsOn)
{
internal readonly string MangaConnectorIdId = mcId.Key;
- protected override BaseWorker[] DoWorkInternal()
+ protected override async Task DoWorkInternal()
{
- if (DbContext.MangaConnectorToManga.Find(MangaConnectorIdId) is not { } mangaConnectorId)
+ if (await DbContext.MangaConnectorToManga.FirstOrDefaultAsync(c => c.Key == MangaConnectorIdId) is not { } mangaConnectorId)
return []; //TODO Exception?
if (!Tranga.TryGetMangaConnector(mangaConnectorId.MangaConnectorName, out MangaConnector? mangaConnector))
return []; //TODO Exception?
- DbContext.Entry(mangaConnectorId).Navigation(nameof(MangaConnectorId.Obj)).Load();
+ await DbContext.Entry(mangaConnectorId).Navigation(nameof(MangaConnectorId.Obj)).LoadAsync(CancellationTokenSource.Token);
Manga manga = mangaConnectorId.Obj;
- DbContext.Entry(manga).Collection(m => m.Chapters).Load();
+ await DbContext.Entry(manga).Collection(m => m.Chapters).LoadAsync(CancellationTokenSource.Token);
// This gets all chapters that are not downloaded
(Chapter, MangaConnectorId)[] allChapters =
@@ -25,13 +26,13 @@ public class RetrieveMangaChaptersFromMangaconnectorWorker(MangaConnectorId mcId) newChapter in allChapters)
{
- if (Tranga.AddChapterToContext(newChapter, DbContext, out Chapter? addedChapter) == false)
+ if (Tranga.AddChapterToContext(newChapter, DbContext, out Chapter? addedChapter, CancellationTokenSource.Token) == false)
continue;
manga.Chapters.Add(addedChapter);
}
Log.Info($"{manga.Chapters.Count} existing + {addedChapters} new chapters.");
- DbContext.Sync();
+ await DbContext.Sync(CancellationTokenSource.Token);
return [];
}
diff --git a/API/Workers/MoveFileOrFolderWorker.cs b/API/Workers/MoveFileOrFolderWorker.cs
index a1cda9e..acd8ff8 100644
--- a/API/Workers/MoveFileOrFolderWorker.cs
+++ b/API/Workers/MoveFileOrFolderWorker.cs
@@ -6,7 +6,7 @@ public class MoveFileOrFolderWorker(string toLocation, string fromLocation, IEnu
public readonly string FromLocation = fromLocation;
public readonly string ToLocation = toLocation;
- protected override BaseWorker[] DoWorkInternal()
+ protected override Task DoWorkInternal()
{
try
{
@@ -14,13 +14,13 @@ public class MoveFileOrFolderWorker(string toLocation, string fromLocation, IEnu
if (!fi.Exists)
{
Log.Error($"File does not exist at {FromLocation}");
- return [];
+ return new Task(() => []);
}
if (File.Exists(ToLocation))//Do not override existing
{
Log.Error($"File already exists at {ToLocation}");
- return [];
+ return new Task(() => []);
}
if(fi.Attributes.HasFlag(FileAttributes.Directory))
MoveDirectory(fi, ToLocation);
@@ -32,7 +32,7 @@ public class MoveFileOrFolderWorker(string toLocation, string fromLocation, IEnu
Log.Error(e);
}
- return [];
+ return new Task(() => []);
}
private void MoveDirectory(FileInfo from, string toLocation)
diff --git a/API/Workers/MoveMangaLibraryWorker.cs b/API/Workers/MoveMangaLibraryWorker.cs
index 255c43b..cb6f3cb 100644
--- a/API/Workers/MoveMangaLibraryWorker.cs
+++ b/API/Workers/MoveMangaLibraryWorker.cs
@@ -1,4 +1,5 @@
using API.Schema.MangaContext;
+using Microsoft.EntityFrameworkCore;
namespace API.Workers;
@@ -7,20 +8,20 @@ public class MoveMangaLibraryWorker(Manga manga, FileLibrary toLibrary, IEnumera
{
internal readonly string MangaId = manga.Key;
internal readonly string LibraryId = toLibrary.Key;
- protected override BaseWorker[] DoWorkInternal()
+ protected override async Task DoWorkInternal()
{
- if (DbContext.Mangas.Find(MangaId) is not { } manga)
+ if (await DbContext.Mangas.FirstOrDefaultAsync(m => m.Key == MangaId, CancellationTokenSource.Token) is not { } manga)
return []; //TODO Exception?
- if (DbContext.FileLibraries.Find(LibraryId) is not { } toLibrary)
+ if (await DbContext.FileLibraries.FirstOrDefaultAsync(l => l.Key == LibraryId, CancellationTokenSource.Token) is not { } toLibrary)
return []; //TODO Exception?
- DbContext.Entry(manga).Collection(m => m.Chapters).Load();
- DbContext.Entry(manga).Navigation(nameof(Manga.Library)).Load();
+ await DbContext.Entry(manga).Collection(m => m.Chapters).LoadAsync(CancellationTokenSource.Token);
+ await DbContext.Entry(manga).Navigation(nameof(Manga.Library)).LoadAsync(CancellationTokenSource.Token);
Dictionary oldPath = manga.Chapters.ToDictionary(c => c, c => c.FullArchiveFilePath);
manga.Library = toLibrary;
- if (DbContext.Sync() is { success: false })
+ if (await DbContext.Sync(CancellationTokenSource.Token) is { success: false })
return [];
return manga.Chapters.Select(c => new MoveFileOrFolderWorker(c.FullArchiveFilePath, oldPath[c])).ToArray();
diff --git a/API/Workers/PeriodicWorkers/CheckForNewChaptersWorker.cs b/API/Workers/PeriodicWorkers/CheckForNewChaptersWorker.cs
index 5866e5c..bbd86d3 100644
--- a/API/Workers/PeriodicWorkers/CheckForNewChaptersWorker.cs
+++ b/API/Workers/PeriodicWorkers/CheckForNewChaptersWorker.cs
@@ -9,7 +9,7 @@ public class CheckForNewChaptersWorker(TimeSpan? interval = null, IEnumerable DoWorkInternal()
{
IQueryable> connectorIdsManga = DbContext.MangaConnectorToManga
.Include(id => id.Obj)
@@ -19,7 +19,7 @@ public class CheckForNewChaptersWorker(TimeSpan? interval = null, IEnumerable mangaConnectorId in connectorIdsManga)
newWorkers.Add(new RetrieveMangaChaptersFromMangaconnectorWorker(mangaConnectorId, Tranga.Settings.DownloadLanguage));
- return newWorkers.ToArray();
+ return new Task(() => newWorkers.ToArray());
}
}
\ No newline at end of file
diff --git a/API/Workers/PeriodicWorkers/MaintenanceWorkers/CleanupMangaCoversWorker.cs b/API/Workers/PeriodicWorkers/MaintenanceWorkers/CleanupMangaCoversWorker.cs
index a507fe4..c30a96a 100644
--- a/API/Workers/PeriodicWorkers/MaintenanceWorkers/CleanupMangaCoversWorker.cs
+++ b/API/Workers/PeriodicWorkers/MaintenanceWorkers/CleanupMangaCoversWorker.cs
@@ -8,11 +8,11 @@ public class CleanupMangaCoversWorker(TimeSpan? interval = null, IEnumerable DoWorkInternal()
{
Log.Info("Removing stale files...");
if (!Directory.Exists(TrangaSettings.coverImageCache))
- return [];
+ return new Task(() => []);
string[] usedFiles = DbContext.Mangas.Select(m => m.CoverFileNameInCache).Where(s => s != null).ToArray()!;
string[] extraneousFiles = new DirectoryInfo(TrangaSettings.coverImageCache).GetFiles()
.Where(f => usedFiles.Contains(f.FullName) == false)
@@ -23,7 +23,6 @@ public class CleanupMangaCoversWorker(TimeSpan? interval = null, IEnumerable(() => []);
}
}
\ No newline at end of file
diff --git a/API/Workers/PeriodicWorkers/MaintenanceWorkers/RemoveOldNotificationsWorker.cs b/API/Workers/PeriodicWorkers/MaintenanceWorkers/RemoveOldNotificationsWorker.cs
index e925105..b50e579 100644
--- a/API/Workers/PeriodicWorkers/MaintenanceWorkers/RemoveOldNotificationsWorker.cs
+++ b/API/Workers/PeriodicWorkers/MaintenanceWorkers/RemoveOldNotificationsWorker.cs
@@ -8,11 +8,12 @@ public class RemoveOldNotificationsWorker(TimeSpan? interval = null, IEnumerable
public DateTime LastExecution { get; set; } = DateTime.UnixEpoch;
public TimeSpan Interval { get; set; } = interval ?? TimeSpan.FromHours(1);
- protected override BaseWorker[] DoWorkInternal()
+ protected override async Task DoWorkInternal()
{
IQueryable toRemove = DbContext.Notifications.Where(n => n.IsSent || DateTime.UtcNow - n.Date > Interval);
DbContext.RemoveRange(toRemove);
- DbContext.Sync();
+
+ await DbContext.Sync(CancellationTokenSource.Token);
return [];
}
diff --git a/API/Workers/PeriodicWorkers/SendNotificationsWorker.cs b/API/Workers/PeriodicWorkers/SendNotificationsWorker.cs
index 0dd27fd..0e4edd1 100644
--- a/API/Workers/PeriodicWorkers/SendNotificationsWorker.cs
+++ b/API/Workers/PeriodicWorkers/SendNotificationsWorker.cs
@@ -8,7 +8,7 @@ public class SendNotificationsWorker(TimeSpan? interval = null, IEnumerable DoWorkInternal()
{
NotificationConnector[] connectors = DbContext.NotificationConnectors.ToArray();
Notification[] notifications = DbContext.Notifications.Where(n => n.IsSent == false).ToArray();
@@ -22,7 +22,7 @@ public class SendNotificationsWorker(TimeSpan? interval = null, IEnumerable DoWorkInternal()
{
IQueryable> mangaConnectorIds = DbContext.MangaConnectorToChapter
.Include(id => id.Obj)
@@ -19,6 +19,6 @@ public class StartNewChapterDownloadsWorker(TimeSpan? interval = null, IEnumerab
foreach (MangaConnectorId mangaConnectorId in mangaConnectorIds)
newWorkers.Add(new DownloadChapterFromMangaconnectorWorker(mangaConnectorId));
- return newWorkers.ToArray();
+ return new Task(() => newWorkers.ToArray());
}
}
\ No newline at end of file
diff --git a/API/Workers/PeriodicWorkers/UpdateChaptersDownloadedWorker.cs b/API/Workers/PeriodicWorkers/UpdateChaptersDownloadedWorker.cs
index 9248b3e..e493d17 100644
--- a/API/Workers/PeriodicWorkers/UpdateChaptersDownloadedWorker.cs
+++ b/API/Workers/PeriodicWorkers/UpdateChaptersDownloadedWorker.cs
@@ -8,12 +8,12 @@ public class UpdateChaptersDownloadedWorker(TimeSpan? interval = null, IEnumerab
{
public DateTime LastExecution { get; set; } = DateTime.UnixEpoch;
public TimeSpan Interval { get; set; } = interval??TimeSpan.FromMinutes(60);
- protected override BaseWorker[] DoWorkInternal()
+ protected override async Task DoWorkInternal()
{
foreach (Chapter dbContextChapter in DbContext.Chapters.Include(c => c.ParentManga))
dbContextChapter.Downloaded = dbContextChapter.CheckDownloaded();
- DbContext.Sync();
+ await DbContext.Sync(CancellationTokenSource.Token);
return [];
}
}
\ No newline at end of file
diff --git a/API/Workers/PeriodicWorkers/UpdateCoversWorker.cs b/API/Workers/PeriodicWorkers/UpdateCoversWorker.cs
index e872a87..5f7be48 100644
--- a/API/Workers/PeriodicWorkers/UpdateCoversWorker.cs
+++ b/API/Workers/PeriodicWorkers/UpdateCoversWorker.cs
@@ -9,11 +9,11 @@ public class UpdateCoversWorker(TimeSpan? interval = null, IEnumerable DoWorkInternal()
{
List workers = new();
foreach (MangaConnectorId mangaConnectorId in DbContext.MangaConnectorToManga)
workers.Add(new DownloadCoverFromMangaconnectorWorker(mangaConnectorId));
- return workers.ToArray();
+ return new Task(() => workers.ToArray());
}
}
\ No newline at end of file
diff --git a/API/Workers/PeriodicWorkers/UpdateMetadataWorker.cs b/API/Workers/PeriodicWorkers/UpdateMetadataWorker.cs
index 6ded373..e3aa9e0 100644
--- a/API/Workers/PeriodicWorkers/UpdateMetadataWorker.cs
+++ b/API/Workers/PeriodicWorkers/UpdateMetadataWorker.cs
@@ -11,7 +11,7 @@ public class UpdateMetadataWorker(TimeSpan? interval = null, IEnumerable DoWorkInternal()
{
IQueryable mangaIds = DbContext.MangaConnectorToManga
.Where(m => m.UseForDownload)
@@ -22,9 +22,9 @@ public class UpdateMetadataWorker(TimeSpan? interval = null, IEnumerable id == e.MangaId));
foreach (MetadataEntry metadataEntry in metadataEntriesToUpdate)
- metadataEntry.MetadataFetcher.UpdateMetadata(metadataEntry, DbContext);
+ await metadataEntry.MetadataFetcher.UpdateMetadata(metadataEntry, DbContext, CancellationTokenSource.Token);
- DbContext.Sync();
+ await DbContext.Sync(CancellationTokenSource.Token);
return [];
}