mirror of
https://github.com/C9Glax/tranga.git
synced 2025-06-14 07:17:54 +02:00
MangaConnectors do not have to return an Object with 6 Parameters.
Job-Start Logic readable and optimized More robust Database design
This commit is contained in:
@ -2,15 +2,17 @@
|
||||
using API.Schema;
|
||||
using API.Schema.Jobs;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
[ApiVersion(2)]
|
||||
[ApiController]
|
||||
[Route("v{version:apiVersion}/[controller]")]
|
||||
public class JobController(PgsqlContext context) : Controller
|
||||
public class JobController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns all Jobs
|
||||
@ -102,7 +104,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
/// <param name="MangaId">ID of Manga</param>
|
||||
/// <param name="record">Job-Configuration</param>
|
||||
/// <response code="201">Job-IDs</response>
|
||||
/// <response code="400">Could not find Library with ID</response>
|
||||
/// <response code="400">Could not find ToLibrary with ID</response>
|
||||
/// <response code="404">Could not find Manga with ID</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPut("DownloadAvailableChaptersJob/{MangaId}")]
|
||||
@ -110,7 +112,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType(Status400BadRequest)]
|
||||
[ProducesResponseType(Status404NotFound)]
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateDownloadAvailableChaptersJob(string MangaId, [FromBody]DownloadAvailableJobsRecord record)
|
||||
public IActionResult CreateDownloadAvailableChaptersJob(string MangaId, [FromBody]DownloadAvailableChaptersJobRecord record)
|
||||
{
|
||||
if (context.Mangas.Find(MangaId) is not { } m)
|
||||
return NotFound();
|
||||
@ -126,13 +128,13 @@ public class JobController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
Job job = new DownloadAvailableChaptersJob(record.recurrenceTimeMs, MangaId);
|
||||
Job dep = new RetrieveChaptersJob(record.recurrenceTimeMs, MangaId, job.JobId);
|
||||
job.DependsOnJobsIds?.Add(dep.JobId);
|
||||
return AddJobs([dep, job]);
|
||||
Job retrieveChapters = new RetrieveChaptersJob(m, record.language, record.recurrenceTimeMs);
|
||||
Job downloadChapters = new DownloadAvailableChaptersJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters]);
|
||||
return AddJobs([retrieveChapters, downloadChapters]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -148,9 +150,9 @@ public class JobController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateNewDownloadChapterJob(string ChapterId)
|
||||
{
|
||||
if(context.Chapters.Find(ChapterId) is null)
|
||||
if(context.Chapters.Find(ChapterId) is not { } c)
|
||||
return NotFound();
|
||||
Job job = new DownloadSingleChapterJob(ChapterId);
|
||||
Job job = new DownloadSingleChapterJob(c);
|
||||
return AddJobs([job]);
|
||||
}
|
||||
|
||||
@ -167,9 +169,9 @@ public class JobController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateUpdateFilesDownloadedJob(string MangaId)
|
||||
{
|
||||
if(context.Mangas.Find(MangaId) is null)
|
||||
if(context.Mangas.Find(MangaId) is not { } m)
|
||||
return NotFound();
|
||||
Job job = new UpdateFilesDownloadedJob(0, MangaId);
|
||||
Job job = new UpdateFilesDownloadedJob(m, 0);
|
||||
return AddJobs([job]);
|
||||
}
|
||||
|
||||
@ -183,8 +185,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateUpdateAllFilesDownloadedJob()
|
||||
{
|
||||
List<string> ids = context.Mangas.Select(m => m.MangaId).ToList();
|
||||
List<UpdateFilesDownloadedJob> jobs = ids.Select(id => new UpdateFilesDownloadedJob(0, id)).ToList();
|
||||
List<UpdateFilesDownloadedJob> jobs = context.Mangas.Select(m => new UpdateFilesDownloadedJob(m, 0, null, null)).ToList();
|
||||
try
|
||||
{
|
||||
context.Jobs.AddRange(jobs);
|
||||
@ -193,12 +194,13 @@ public class JobController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new UpdateMetadataJob
|
||||
/// Not Implemented: Create a new UpdateMetadataJob
|
||||
/// </summary>
|
||||
/// <param name="MangaId">ID of the Manga</param>
|
||||
/// <response code="201">Job-IDs</response>
|
||||
@ -210,14 +212,11 @@ public class JobController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateUpdateMetadataJob(string MangaId)
|
||||
{
|
||||
if(context.Mangas.Find(MangaId) is null)
|
||||
return NotFound();
|
||||
Job job = new UpdateMetadataJob(0, MangaId);
|
||||
return AddJobs([job]);
|
||||
return StatusCode(Status501NotImplemented);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new UpdateMetadataJob for all Manga
|
||||
/// Not Implemented: Create a new UpdateMetadataJob for all Manga
|
||||
/// </summary>
|
||||
/// <response code="201">Job-IDs</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
@ -226,18 +225,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult CreateUpdateAllMetadataJob()
|
||||
{
|
||||
List<string> ids = context.Mangas.Select(m => m.MangaId).ToList();
|
||||
List<UpdateMetadataJob> jobs = ids.Select(id => new UpdateMetadataJob(0, id)).ToList();
|
||||
try
|
||||
{
|
||||
context.Jobs.AddRange(jobs);
|
||||
context.SaveChanges();
|
||||
return Created();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
return StatusCode(Status501NotImplemented);
|
||||
}
|
||||
|
||||
private IActionResult AddJobs(Job[] jobs)
|
||||
@ -250,6 +238,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -269,8 +258,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
Job? ret = context.Jobs.Find(JobId);
|
||||
if(ret is null)
|
||||
if(context.Jobs.Find(JobId) is not { } ret)
|
||||
return NotFound();
|
||||
|
||||
context.Remove(ret);
|
||||
@ -279,6 +267,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -322,6 +311,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -354,6 +344,7 @@ public class JobController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -367,6 +358,6 @@ public class JobController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType(Status501NotImplemented)]
|
||||
public IActionResult StopJob(string JobId)
|
||||
{
|
||||
return StatusCode(501);
|
||||
return StatusCode(Status501NotImplemented);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using API.Schema;
|
||||
using API.Schema.LibraryConnectors;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
|
||||
@ -9,10 +10,10 @@ namespace API.Controllers;
|
||||
[ApiVersion(2)]
|
||||
[ApiController]
|
||||
[Route("v{v:apiVersion}/[controller]")]
|
||||
public class LibraryConnectorController(PgsqlContext context) : Controller
|
||||
public class LibraryConnectorController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all configured Library-Connectors
|
||||
/// Gets all configured ToLibrary-Connectors
|
||||
/// </summary>
|
||||
/// <response code="200"></response>
|
||||
[HttpGet]
|
||||
@ -24,9 +25,9 @@ public class LibraryConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns Library-Connector with requested ID
|
||||
/// Returns ToLibrary-Connector with requested ID
|
||||
/// </summary>
|
||||
/// <param name="LibraryControllerId">Library-Connector-ID</param>
|
||||
/// <param name="LibraryControllerId">ToLibrary-Connector-ID</param>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="404">Connector with ID not found.</response>
|
||||
[HttpGet("{LibraryControllerId}")]
|
||||
@ -43,9 +44,9 @@ public class LibraryConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Library-Connector
|
||||
/// Creates a new ToLibrary-Connector
|
||||
/// </summary>
|
||||
/// <param name="libraryConnector">Library-Connector</param>
|
||||
/// <param name="libraryConnector">ToLibrary-Connector</param>
|
||||
/// <response code="201"></response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPut]
|
||||
@ -61,14 +62,15 @@ public class LibraryConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the Library-Connector with the requested ID
|
||||
/// Deletes the ToLibrary-Connector with the requested ID
|
||||
/// </summary>
|
||||
/// <param name="LibraryControllerId">Library-Connector-ID</param>
|
||||
/// <param name="LibraryControllerId">ToLibrary-Connector-ID</param>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="404">Connector with ID not found.</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
@ -90,6 +92,7 @@ public class LibraryConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using API.APIEndpointRecords;
|
||||
using API.Schema;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
|
||||
@ -9,7 +10,7 @@ namespace API.Controllers;
|
||||
[ApiVersion(2)]
|
||||
[ApiController]
|
||||
[Route("v{v:apiVersion}/[controller]")]
|
||||
public class LocalLibrariesController(PgsqlContext context) : Controller
|
||||
public class LocalLibrariesController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
[HttpGet]
|
||||
[ProducesResponseType<LocalLibrary[]>(Status200OK, "application/json")]
|
||||
@ -52,6 +53,7 @@ public class LocalLibrariesController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -79,6 +81,7 @@ public class LocalLibrariesController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -106,6 +109,7 @@ public class LocalLibrariesController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -128,6 +132,7 @@ public class LocalLibrariesController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -151,6 +156,7 @@ public class LocalLibrariesController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using API.Schema;
|
||||
using API.Schema.MangaConnectors;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
|
||||
@ -9,7 +10,7 @@ namespace API.Controllers;
|
||||
[ApiVersion(2)]
|
||||
[ApiController]
|
||||
[Route("v{v:apiVersion}/[controller]")]
|
||||
public class MangaConnectorController(PgsqlContext context) : Controller
|
||||
public class MangaConnectorController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all available Connectors (Scanlation-Sites)
|
||||
@ -74,6 +75,7 @@ public class MangaConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,21 @@
|
||||
using API.Schema;
|
||||
using API.Schema.Jobs;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SixLabors.ImageSharp.Processing.Processors.Transforms;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
[ApiVersion(2)]
|
||||
[ApiController]
|
||||
[Route("v{v:apiVersion}/[controller]")]
|
||||
public class MangaController(PgsqlContext context) : Controller
|
||||
public class MangaController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns all cached Manga
|
||||
@ -82,6 +84,7 @@ public class MangaController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -287,11 +290,12 @@ public class MangaController(PgsqlContext context) : Controller
|
||||
|
||||
return Ok(max);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Configure the cut-off for Manga
|
||||
/// </summary>
|
||||
/// <param name="MangaId">Manga-ID</param>
|
||||
/// <param name="chapterThreshold">Threshold (Chapter Number)</param>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="404">Manga with ID not found.</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
@ -307,21 +311,22 @@ public class MangaController(PgsqlContext context) : Controller
|
||||
|
||||
try
|
||||
{
|
||||
m.IgnoreChapterBefore = chapterThreshold;
|
||||
m.IgnoreChaptersBefore = chapterThreshold;
|
||||
context.SaveChanges();
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move Manga to different Library
|
||||
/// Move Manga to different ToLibrary
|
||||
/// </summary>
|
||||
/// <param name="MangaId">Manga-ID</param>
|
||||
/// <param name="LibraryId">Library-Id</param>
|
||||
/// <param name="LibraryId">ToLibrary-Id</param>
|
||||
/// <response code="202">Folder is going to be moved</response>
|
||||
/// <response code="404">MangaId or LibraryId not found</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
@ -331,24 +336,23 @@ public class MangaController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult MoveFolder(string MangaId, string LibraryId)
|
||||
{
|
||||
Manga? manga = context.Mangas.Find(MangaId);
|
||||
if (manga is null)
|
||||
if (context.Mangas.Find(MangaId) is not { } manga)
|
||||
return NotFound();
|
||||
LocalLibrary? library = context.LocalLibraries.Find(LibraryId);
|
||||
if (library is null)
|
||||
if(context.LocalLibraries.Find(LibraryId) is not { } library)
|
||||
return NotFound();
|
||||
|
||||
MoveMangaLibraryJob dep = new (MangaId, LibraryId);
|
||||
UpdateFilesDownloadedJob up = new (0, manga.MangaId, null, [dep.JobId]);
|
||||
|
||||
MoveMangaLibraryJob moveLibrary = new(manga, library);
|
||||
UpdateFilesDownloadedJob updateDownloadedFiles = new(manga, 0, dependsOnJobs: [moveLibrary]);
|
||||
|
||||
try
|
||||
{
|
||||
context.Jobs.AddRange([dep, up]);
|
||||
context.Jobs.AddRange(moveLibrary, updateDownloadedFiles);
|
||||
context.SaveChanges();
|
||||
return Accepted();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ using API.APIEndpointRecords;
|
||||
using API.Schema;
|
||||
using API.Schema.NotificationConnectors;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
|
||||
@ -12,7 +13,7 @@ namespace API.Controllers;
|
||||
[ApiController]
|
||||
[Produces("application/json")]
|
||||
[Route("v{v:apiVersion}/[controller]")]
|
||||
public class NotificationConnectorController(PgsqlContext context) : Controller
|
||||
public class NotificationConnectorController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all configured Notification-Connectors
|
||||
@ -69,6 +70,7 @@ public class NotificationConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
@ -209,6 +211,7 @@ public class NotificationConnectorController(PgsqlContext context) : Controller
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
using API.Schema;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
[ApiVersion(2)]
|
||||
[ApiController]
|
||||
[Route("v{v:apiVersion}/[controller]")]
|
||||
public class QueryController(PgsqlContext context) : Controller
|
||||
public class QueryController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the Author-Information for Author-ID
|
||||
@ -32,13 +34,16 @@ public class QueryController(PgsqlContext context) : Controller
|
||||
/// </summary>
|
||||
/// <param name="AuthorId">Author-ID</param>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="404">Author not found</response>
|
||||
[HttpGet("Mangas/WithAuthorId/{AuthorId}")]
|
||||
[ProducesResponseType<Manga[]>(Status200OK, "application/json")]
|
||||
public IActionResult GetMangaWithAuthorIds(string AuthorId)
|
||||
{
|
||||
return Ok(context.Mangas.Where(m => m.AuthorIds.Contains(AuthorId)));
|
||||
if(context.Authors.Find(AuthorId) is not { } a)
|
||||
return NotFound();
|
||||
return Ok(context.Mangas.Where(m => m.Authors.Contains(a)));
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Returns Link-Information for Link-Id
|
||||
/// </summary>
|
||||
@ -71,18 +76,21 @@ public class QueryController(PgsqlContext context) : Controller
|
||||
if (ret is null)
|
||||
return NotFound();
|
||||
return Ok(ret);
|
||||
}
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Returns all Manga with Tag
|
||||
/// </summary>
|
||||
/// <param name="Tag"></param>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="404">Tag not found</response>
|
||||
[HttpGet("Mangas/WithTag/{Tag}")]
|
||||
[ProducesResponseType<Manga[]>(Status200OK, "application/json")]
|
||||
public IActionResult GetMangasWithTag(string Tag)
|
||||
{
|
||||
return Ok(context.Mangas.Where(m => m.Tags.Contains(Tag)));
|
||||
if(context.Tags.Find(Tag) is not { } t)
|
||||
return NotFound();
|
||||
return Ok(context.Mangas.Where(m => m.MangaTags.Contains(t)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2,85 +2,53 @@ using API.Schema;
|
||||
using API.Schema.Jobs;
|
||||
using API.Schema.MangaConnectors;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
[ApiVersion(2)]
|
||||
[ApiController]
|
||||
[Route("v{v:apiVersion}/[controller]")]
|
||||
public class SearchController(PgsqlContext context) : Controller
|
||||
public class SearchController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initiate a search for a Manga on all Connectors
|
||||
/// </summary>
|
||||
/// <param name="name">Name/Title of the Manga</param>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPost("Name")]
|
||||
[ProducesResponseType<Manga[]>(Status200OK, "application/json")]
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult SearchMangaGlobal([FromBody]string name)
|
||||
{
|
||||
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> allManga = new();
|
||||
foreach (MangaConnector contextMangaConnector in context.MangaConnectors.Where(connector => connector.Enabled))
|
||||
allManga.AddRange(contextMangaConnector.GetManga(name));
|
||||
|
||||
List<Manga> retMangas = new();
|
||||
foreach ((Manga? manga, List<Author>? authors, List<MangaTag>? tags, List<Link>? links, List<MangaAltTitle>? altTitles) in allManga)
|
||||
{
|
||||
try
|
||||
{
|
||||
Manga? add = AddMangaToContext(manga, authors, tags, links, altTitles);
|
||||
if(add is not null)
|
||||
retMangas.Add(add);
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
return StatusCode(500, e);
|
||||
}
|
||||
}
|
||||
return Ok(retMangas.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initiate a search for a Manga on a specific Connector
|
||||
/// </summary>
|
||||
/// <param name="MangaConnectorName">Manga-Connector-ID</param>
|
||||
/// <param name="name">Name/Title of the Manga</param>
|
||||
/// <param name="MangaConnectorName"></param>
|
||||
/// <param name="Query"></param>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="404">MangaConnector with ID not found</response>
|
||||
/// <response code="406">MangaConnector with ID is disabled</response>
|
||||
/// <response code="500">Error during Database Operation</response>
|
||||
[HttpPost("{MangaConnectorName}")]
|
||||
[HttpPost("{MangaConnectorName}/{Query}")]
|
||||
[ProducesResponseType<Manga[]>(Status200OK, "application/json")]
|
||||
[ProducesResponseType(Status404NotFound)]
|
||||
[ProducesResponseType(Status406NotAcceptable)]
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult SearchManga(string MangaConnectorName, [FromBody]string name)
|
||||
public IActionResult SearchManga(string MangaConnectorName, string Query)
|
||||
{
|
||||
MangaConnector? connector = context.MangaConnectors.Find(MangaConnectorName);
|
||||
if (connector is null)
|
||||
if(context.MangaConnectors.Find(MangaConnectorName) is not { } connector)
|
||||
return NotFound();
|
||||
else if (connector.Enabled is false)
|
||||
return StatusCode(406);
|
||||
return StatusCode(Status406NotAcceptable);
|
||||
|
||||
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] mangas = connector.GetManga(name);
|
||||
Manga[] mangas = connector.SearchManga(Query);
|
||||
List<Manga> retMangas = new();
|
||||
foreach ((Manga? manga, List<Author>? authors, List<MangaTag>? tags, List<Link>? links, List<MangaAltTitle>? altTitles) in mangas)
|
||||
foreach (Manga manga in mangas)
|
||||
{
|
||||
try
|
||||
{
|
||||
Manga? add = AddMangaToContext(manga, authors, tags, links, altTitles);
|
||||
if(add is not null)
|
||||
if(AddMangaToContext(manga) is { } add)
|
||||
retMangas.Add(add);
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
return StatusCode(500, e.Message);
|
||||
Log.Error(e);
|
||||
return StatusCode(Status500InternalServerError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,98 +72,77 @@ public class SearchController(PgsqlContext context) : Controller
|
||||
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
|
||||
public IActionResult GetMangaFromUrl([FromBody]string url)
|
||||
{
|
||||
List<MangaConnector> connectors = context.MangaConnectors.AsEnumerable().Where(c => c.ValidateUrl(url)).ToList();
|
||||
List<MangaConnector> connectors = context.MangaConnectors.AsEnumerable().Where(c => c.UrlMatchesConnector(url)).ToList();
|
||||
if (connectors.Count == 0)
|
||||
return NotFound();
|
||||
else if (connectors.Count > 1)
|
||||
return StatusCode(Status300MultipleChoices);
|
||||
|
||||
(Manga manga, List<Author>? authors, List<MangaTag>? tags, List<Link>? links, List<MangaAltTitle>? altTitles)? x = connectors.First().GetMangaFromUrl(url);
|
||||
if (x is null)
|
||||
if(connectors.First().GetMangaFromUrl(url) is not { } manga)
|
||||
return BadRequest();
|
||||
try
|
||||
{
|
||||
Manga? add = AddMangaToContext(x.Value.manga, x.Value.authors, x.Value.tags, x.Value.links, x.Value.altTitles);
|
||||
if (add is not null)
|
||||
if(AddMangaToContext(manga) is { } add)
|
||||
return Ok(add);
|
||||
return StatusCode(500);
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private Manga? AddMangaToContext(Manga? manga, List<Author>? authors, List<MangaTag>? tags, List<Link>? links,
|
||||
List<MangaAltTitle>? altTitles)
|
||||
private Manga? AddMangaToContext(Manga manga)
|
||||
{
|
||||
if (manga is null)
|
||||
return null;
|
||||
|
||||
Manga? existing = context.Mangas.Find(manga.MangaId);
|
||||
|
||||
if (tags is not null)
|
||||
IEnumerable<MangaTag> mergedTags = manga.MangaTags.Select(mt =>
|
||||
{
|
||||
IEnumerable<MangaTag> mergedTags = tags.Select(mt =>
|
||||
{
|
||||
MangaTag? inDb = context.Tags.Find(mt.Tag);
|
||||
return inDb ?? mt;
|
||||
});
|
||||
manga.MangaTags = mergedTags.ToList();
|
||||
IEnumerable<MangaTag> newTags = manga.MangaTags
|
||||
.Where(mt => !context.Tags.Select(t => t.Tag).Contains(mt.Tag));
|
||||
context.Tags.AddRange(newTags);
|
||||
}
|
||||
MangaTag? inDb = context.Tags.Find(mt.Tag);
|
||||
return inDb ?? mt;
|
||||
});
|
||||
manga.MangaTags = mergedTags.ToList();
|
||||
|
||||
if (authors is not null)
|
||||
IEnumerable<Author> mergedAuthors = manga.Authors.Select(ma =>
|
||||
{
|
||||
IEnumerable<Author> mergedAuthors = authors.Select(ma =>
|
||||
{
|
||||
Author? inDb = context.Authors.Find(ma.AuthorId);
|
||||
return inDb ?? ma;
|
||||
});
|
||||
manga.Authors = mergedAuthors.ToList();
|
||||
IEnumerable<Author> newAuthors = manga.Authors
|
||||
.Where(ma => !context.Authors.Select(a => a.AuthorId).Contains(ma.AuthorId));
|
||||
context.Authors.AddRange(newAuthors);
|
||||
}
|
||||
Author? inDb = context.Authors.Find(ma.AuthorId);
|
||||
return inDb ?? ma;
|
||||
});
|
||||
manga.Authors = mergedAuthors.ToList();
|
||||
|
||||
if (links is not null)
|
||||
/*
|
||||
IEnumerable<Link> mergedLinks = manga.Links.Select(ml =>
|
||||
{
|
||||
IEnumerable<Link> mergedLinks = links.Select(ml =>
|
||||
{
|
||||
Link? inDb = context.Links.Find(ml.LinkId);
|
||||
return inDb ?? ml;
|
||||
});
|
||||
manga.Links = mergedLinks.ToList();
|
||||
IEnumerable<Link> newLinks = manga.Links
|
||||
.Where(ml => !context.Links.Select(l => l.LinkId).Contains(ml.LinkId));
|
||||
context.Links.AddRange(newLinks);
|
||||
}
|
||||
Link? inDb = context.Links.Find(ml.LinkId);
|
||||
return inDb ?? ml;
|
||||
});
|
||||
manga.Links = mergedLinks.ToList();
|
||||
|
||||
if (altTitles is not null)
|
||||
IEnumerable<MangaAltTitle> mergedAltTitles = manga.AltTitles.Select(mat =>
|
||||
{
|
||||
IEnumerable<MangaAltTitle> mergedAltTitles = altTitles.Select(mat =>
|
||||
MangaAltTitle? inDb = context.AltTitles.Find(mat.AltTitleId);
|
||||
return inDb ?? mat;
|
||||
});
|
||||
manga.AltTitles = mergedAltTitles.ToList();
|
||||
*/
|
||||
try
|
||||
{
|
||||
|
||||
if (context.Mangas.Find(manga.MangaId) is { } r)
|
||||
{
|
||||
MangaAltTitle? inDb = context.AltTitles.Find(mat.AltTitleId);
|
||||
return inDb ?? mat;
|
||||
});
|
||||
manga.AltTitles = mergedAltTitles.ToList();
|
||||
IEnumerable<MangaAltTitle> newAltTitles = manga.AltTitles
|
||||
.Where(mat => !context.AltTitles.Select(at => at.AltTitleId).Contains(mat.AltTitleId));
|
||||
context.AltTitles.AddRange(newAltTitles);
|
||||
}
|
||||
|
||||
existing?.UpdateWithInfo(manga);
|
||||
if(existing is not null)
|
||||
context.Mangas.Update(existing);
|
||||
else
|
||||
context.Mangas.Remove(r);
|
||||
context.SaveChanges();
|
||||
}
|
||||
context.Mangas.Add(manga);
|
||||
|
||||
context.Jobs.Add(new DownloadMangaCoverJob(manga.MangaId));
|
||||
context.Jobs.Add(new RetrieveChaptersJob(0, manga.MangaId));
|
||||
|
||||
context.SaveChanges();
|
||||
return existing ?? manga;
|
||||
context.Jobs.Add(new DownloadMangaCoverJob(manga));
|
||||
context.SaveChanges();
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return null;
|
||||
}
|
||||
return manga;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using API.Schema;
|
||||
using API.Schema.Jobs;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
@ -11,7 +12,7 @@ namespace API.Controllers;
|
||||
[ApiVersion(2)]
|
||||
[ApiController]
|
||||
[Route("v{v:apiVersion}/[controller]")]
|
||||
public class SettingsController(PgsqlContext context) : Controller
|
||||
public class SettingsController(PgsqlContext context, ILog Log) : Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all Settings
|
||||
@ -252,14 +253,16 @@ public class SettingsController(PgsqlContext context) : Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<Chapter, string> oldPaths = context.Chapters.ToDictionary(c => c, c => c.FullArchiveFilePath);
|
||||
TrangaSettings.UpdateChapterNamingScheme(namingScheme);
|
||||
MoveFileOrFolderJob[] newJobs =
|
||||
context.Chapters.Where(c => c.Downloaded).Select(c => c.UpdateArchiveFileName()).Where(x => x != null).ToArray()!;
|
||||
MoveFileOrFolderJob[] newJobs = oldPaths
|
||||
.Select(kv => new MoveFileOrFolderJob(kv.Value, kv.Key.FullArchiveFilePath)).ToArray();
|
||||
context.Jobs.AddRange(newJobs);
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
return StatusCode(500, e);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user