From 3a46d0fd24a7d03389859cacf268082a31479c05 Mon Sep 17 00:00:00 2001 From: glax Date: Mon, 21 Jul 2025 11:42:17 +0200 Subject: [PATCH] Disable LazyLoading Remove MangaConnectors from Database --- API/Controllers/MangaConnectorController.cs | 14 +-- API/Controllers/MangaController.cs | 6 +- API/Controllers/SearchController.cs | 6 +- .../MangaConnectors/ComickIo.cs | 3 +- .../MangaConnectors/Global.cs | 20 ++-- .../MangaConnectors/MangaConnector.cs | 3 +- .../MangaConnectors/MangaDex.cs | 3 +- ....cs => 20250721093858_Initial.Designer.cs} | 100 +++++++----------- ...3_Initial.cs => 20250721093858_Initial.cs} | 32 +----- .../Manga/MangaContextModelSnapshot.cs | 98 +++++++---------- API/Program.cs | 10 +- API/Schema/MangaContext/Chapter.cs | 27 +---- API/Schema/MangaContext/Manga.cs | 33 +----- API/Schema/MangaContext/MangaConnectorId.cs | 36 +------ API/Schema/MangaContext/MangaContext.cs | 31 +----- API/Tranga.cs | 9 ++ ...DownloadChapterFromMangaconnectorWorker.cs | 20 ++-- .../DownloadCoverFromMangaconnectorWorker.cs | 11 +- ...veMangaChaptersFromMangaconnectorWorker.cs | 11 +- .../StartNewChapterDownloadsWorker.cs | 5 +- 20 files changed, 167 insertions(+), 311 deletions(-) rename API/{Schema/MangaContext => }/MangaConnectors/ComickIo.cs (99%) rename API/{Schema/MangaContext => }/MangaConnectors/Global.cs (66%) rename API/{Schema/MangaContext => }/MangaConnectors/MangaConnector.cs (97%) rename API/{Schema/MangaContext => }/MangaConnectors/MangaDex.cs (99%) rename API/Migrations/Manga/{20250703192023_Initial.Designer.cs => 20250721093858_Initial.Designer.cs} (92%) rename API/Migrations/Manga/{20250703192023_Initial.cs => 20250721093858_Initial.cs} (92%) diff --git a/API/Controllers/MangaConnectorController.cs b/API/Controllers/MangaConnectorController.cs index bf7436f..7e6cba8 100644 --- a/API/Controllers/MangaConnectorController.cs +++ b/API/Controllers/MangaConnectorController.cs @@ -1,5 +1,5 @@ -using API.Schema.MangaContext; -using API.Schema.MangaContext.MangaConnectors; +using API.MangaConnectors; +using API.Schema.MangaContext; using Asp.Versioning; using Microsoft.AspNetCore.Mvc; using static Microsoft.AspNetCore.Http.StatusCodes; @@ -20,7 +20,7 @@ public class MangaConnectorController(MangaContext context) : Controller [ProducesResponseType(Status200OK, "application/json")] public IActionResult GetConnectors() { - return Ok(context.MangaConnectors.Select(c => c.Name).ToArray()); + return Ok(Tranga.MangaConnectors.Select(c => c.Name).ToArray()); } /// @@ -34,7 +34,7 @@ public class MangaConnectorController(MangaContext context) : Controller [ProducesResponseType(Status404NotFound)] public IActionResult GetConnector(string MangaConnectorName) { - if(context.MangaConnectors.Find(MangaConnectorName) is not { } connector) + if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals(MangaConnectorName, StringComparison.InvariantCultureIgnoreCase)) is not { } connector) return NotFound(); return Ok(connector); @@ -49,7 +49,7 @@ public class MangaConnectorController(MangaContext context) : Controller public IActionResult GetEnabledConnectors() { - return Ok(context.MangaConnectors.Where(c => c.Enabled).ToArray()); + return Ok(Tranga.MangaConnectors.Where(c => c.Enabled).ToArray()); } /// @@ -61,7 +61,7 @@ public class MangaConnectorController(MangaContext context) : Controller public IActionResult GetDisabledConnectors() { - return Ok(context.MangaConnectors.Where(c => c.Enabled == false).ToArray()); + return Ok(Tranga.MangaConnectors.Where(c => c.Enabled == false).ToArray()); } /// @@ -78,7 +78,7 @@ public class MangaConnectorController(MangaContext context) : Controller [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult SetEnabled(string MangaConnectorName, bool Enabled) { - if(context.MangaConnectors.Find(MangaConnectorName) is not { } connector) + if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals(MangaConnectorName, StringComparison.InvariantCultureIgnoreCase)) is not { } connector) return NotFound(); connector.Enabled = Enabled; diff --git a/API/Controllers/MangaController.cs b/API/Controllers/MangaController.cs index c2da1d3..9722da6 100644 --- a/API/Controllers/MangaController.cs +++ b/API/Controllers/MangaController.cs @@ -1,5 +1,5 @@ -using API.Schema.MangaContext; -using API.Schema.MangaContext.MangaConnectors; +using API.MangaConnectors; +using API.Schema.MangaContext; using API.Workers; using Asp.Versioning; using Microsoft.AspNetCore.Mvc; @@ -368,7 +368,7 @@ public class MangaController(MangaContext context) : Controller { if (context.Mangas.Find(MangaId) is null) return NotFound(nameof(MangaId)); - if(context.MangaConnectors.Find(MangaConnectorName) is null) + if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals(MangaConnectorName, StringComparison.InvariantCultureIgnoreCase)) is not { } connector) return NotFound(nameof(MangaConnectorName)); if (context.MangaConnectorToManga.FirstOrDefault(id => id.MangaConnectorName == MangaConnectorName && id.ObjId == MangaId) is not { } mcId) diff --git a/API/Controllers/SearchController.cs b/API/Controllers/SearchController.cs index 60780cb..4f89d1a 100644 --- a/API/Controllers/SearchController.cs +++ b/API/Controllers/SearchController.cs @@ -1,5 +1,5 @@ +using API.MangaConnectors; using API.Schema.MangaContext; -using API.Schema.MangaContext.MangaConnectors; using Asp.Versioning; using Microsoft.AspNetCore.Mvc; using static Microsoft.AspNetCore.Http.StatusCodes; @@ -26,7 +26,7 @@ public class SearchController(MangaContext context) : Controller [ProducesResponseType(Status406NotAcceptable)] public IActionResult SearchManga(string MangaConnectorName, string Query) { - if(context.MangaConnectors.Find(MangaConnectorName) is not { } connector) + if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals(MangaConnectorName, StringComparison.InvariantCultureIgnoreCase)) is not { } connector) return NotFound(); if (connector.Enabled is false) return StatusCode(Status412PreconditionFailed); @@ -56,7 +56,7 @@ public class SearchController(MangaContext context) : Controller [ProducesResponseType(Status500InternalServerError)] public IActionResult GetMangaFromUrl([FromBody]string url) { - if (context.MangaConnectors.Find("Global") is not { } connector) + if(Tranga.MangaConnectors.FirstOrDefault(c => c.Name.Equals("Global", StringComparison.InvariantCultureIgnoreCase)) is not { } connector) return StatusCode(Status500InternalServerError, "Could not find Global Connector."); if(connector.GetMangaFromUrl(url) is not { } manga) diff --git a/API/Schema/MangaContext/MangaConnectors/ComickIo.cs b/API/MangaConnectors/ComickIo.cs similarity index 99% rename from API/Schema/MangaContext/MangaConnectors/ComickIo.cs rename to API/MangaConnectors/ComickIo.cs index a2bac81..b5829b6 100644 --- a/API/Schema/MangaContext/MangaConnectors/ComickIo.cs +++ b/API/MangaConnectors/ComickIo.cs @@ -1,8 +1,9 @@ using System.Text.RegularExpressions; using API.MangaDownloadClients; +using API.Schema.MangaContext; using Newtonsoft.Json.Linq; -namespace API.Schema.MangaContext.MangaConnectors; +namespace API.MangaConnectors; public class ComickIo : MangaConnector { diff --git a/API/Schema/MangaContext/MangaConnectors/Global.cs b/API/MangaConnectors/Global.cs similarity index 66% rename from API/Schema/MangaContext/MangaConnectors/Global.cs rename to API/MangaConnectors/Global.cs index 611e4d5..0d9735d 100644 --- a/API/Schema/MangaContext/MangaConnectors/Global.cs +++ b/API/MangaConnectors/Global.cs @@ -1,17 +1,17 @@ -namespace API.Schema.MangaContext.MangaConnectors; +using API.Schema.MangaContext; + +namespace API.MangaConnectors; public class Global : MangaConnector { - private MangaContext context { get; init; } - public Global(MangaContext context) : base("Global", ["all"], [""], "") + public Global() : base("Global", ["all"], [""], "") { - this.context = context; } public override (Manga, MangaConnectorId)[] SearchManga(string mangaSearchName) { //Get all enabled Connectors - MangaConnector[] enabledConnectors = context.MangaConnectors.Where(c => c.Enabled && c.Name != "Global").ToArray(); + MangaConnector[] enabledConnectors = Tranga.MangaConnectors.Where(c => c.Enabled && c.Name != "Global").ToArray(); //Create Task for each MangaConnector to search simultaneously Task<(Manga, MangaConnectorId)[]>[] tasks = @@ -32,7 +32,7 @@ public class Global : MangaConnector public override (Manga, MangaConnectorId)? GetMangaFromUrl(string url) { - MangaConnector? mc = context.MangaConnectors.ToArray().FirstOrDefault(c => c.UrlMatchesConnector(url)); + MangaConnector? mc = Tranga.MangaConnectors.FirstOrDefault(c => c.UrlMatchesConnector(url)); return mc?.GetMangaFromUrl(url) ?? null; } @@ -44,11 +44,15 @@ public class Global : MangaConnector public override (Chapter, MangaConnectorId)[] GetChapters(MangaConnectorId manga, string? language = null) { - return manga.MangaConnector.GetChapters(manga, language); + if (!Tranga.TryGetMangaConnector(manga.MangaConnectorName, out MangaConnector? mangaConnector)) + return []; + return mangaConnector.GetChapters(manga, language); } internal override string[] GetChapterImageUrls(MangaConnectorId chapterId) { - return chapterId.MangaConnector.GetChapterImageUrls(chapterId); + if (!Tranga.TryGetMangaConnector(chapterId.MangaConnectorName, out MangaConnector? mangaConnector)) + return []; + return mangaConnector.GetChapterImageUrls(chapterId); } } \ No newline at end of file diff --git a/API/Schema/MangaContext/MangaConnectors/MangaConnector.cs b/API/MangaConnectors/MangaConnector.cs similarity index 97% rename from API/Schema/MangaContext/MangaConnectors/MangaConnector.cs rename to API/MangaConnectors/MangaConnector.cs index 3cad612..31fc0b9 100644 --- a/API/Schema/MangaContext/MangaConnectors/MangaConnector.cs +++ b/API/MangaConnectors/MangaConnector.cs @@ -2,11 +2,12 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Text.RegularExpressions; using API.MangaDownloadClients; +using API.Schema.MangaContext; using log4net; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; -namespace API.Schema.MangaContext.MangaConnectors; +namespace API.MangaConnectors; [PrimaryKey("Name")] public abstract class MangaConnector(string name, string[] supportedLanguages, string[] baseUris, string iconUrl) diff --git a/API/Schema/MangaContext/MangaConnectors/MangaDex.cs b/API/MangaConnectors/MangaDex.cs similarity index 99% rename from API/Schema/MangaContext/MangaConnectors/MangaDex.cs rename to API/MangaConnectors/MangaDex.cs index 00e620e..ba10e45 100644 --- a/API/Schema/MangaContext/MangaConnectors/MangaDex.cs +++ b/API/MangaConnectors/MangaDex.cs @@ -1,8 +1,9 @@ using System.Text.RegularExpressions; using API.MangaDownloadClients; +using API.Schema.MangaContext; using Newtonsoft.Json.Linq; -namespace API.Schema.MangaContext.MangaConnectors; +namespace API.MangaConnectors; public class MangaDex : MangaConnector { diff --git a/API/Migrations/Manga/20250703192023_Initial.Designer.cs b/API/Migrations/Manga/20250721093858_Initial.Designer.cs similarity index 92% rename from API/Migrations/Manga/20250703192023_Initial.Designer.cs rename to API/Migrations/Manga/20250721093858_Initial.Designer.cs index b728b26..147503c 100644 --- a/API/Migrations/Manga/20250703192023_Initial.Designer.cs +++ b/API/Migrations/Manga/20250721093858_Initial.Designer.cs @@ -11,7 +11,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace API.Migrations.Manga { [DbContext(typeof(MangaContext))] - [Migration("20250703192023_Initial")] + [Migration("20250721093858_Initial")] partial class Initial { /// @@ -24,6 +24,39 @@ namespace API.Migrations.Manga NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("API.MangaConnectors.MangaConnector", b => + { + b.Property("Name") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.PrimitiveCollection("BaseUris") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("text[]"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IconUrl") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.PrimitiveCollection("SupportedLanguages") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("text[]"); + + b.HasKey("Name"); + + b.ToTable("MangaConnector"); + + b.HasDiscriminator("Name").HasValue("MangaConnector"); + + b.UseTphMappingStrategy(); + }); + modelBuilder.Entity("API.Schema.MangaContext.Author", b => { b.Property("Key") @@ -177,8 +210,6 @@ namespace API.Migrations.Manga b.HasKey("Key"); - b.HasIndex("MangaConnectorName"); - b.HasIndex("ObjId"); b.ToTable("MangaConnectorToChapter"); @@ -213,46 +244,11 @@ namespace API.Migrations.Manga b.HasKey("Key"); - b.HasIndex("MangaConnectorName"); - b.HasIndex("ObjId"); b.ToTable("MangaConnectorToManga"); }); - modelBuilder.Entity("API.Schema.MangaContext.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - modelBuilder.Entity("API.Schema.MangaContext.MangaTag", b => { b.Property("Tag") @@ -332,23 +328,23 @@ namespace API.Migrations.Manga b.ToTable("MangaTagToManga"); }); - modelBuilder.Entity("API.Schema.MangaContext.MangaConnectors.ComickIo", b => + modelBuilder.Entity("API.MangaConnectors.ComickIo", b => { - b.HasBaseType("API.Schema.MangaContext.MangaConnectors.MangaConnector"); + b.HasBaseType("API.MangaConnectors.MangaConnector"); b.HasDiscriminator().HasValue("ComickIo"); }); - modelBuilder.Entity("API.Schema.MangaContext.MangaConnectors.Global", b => + modelBuilder.Entity("API.MangaConnectors.Global", b => { - b.HasBaseType("API.Schema.MangaContext.MangaConnectors.MangaConnector"); + b.HasBaseType("API.MangaConnectors.MangaConnector"); b.HasDiscriminator().HasValue("Global"); }); - modelBuilder.Entity("API.Schema.MangaContext.MangaConnectors.MangaDex", b => + modelBuilder.Entity("API.MangaConnectors.MangaDex", b => { - b.HasBaseType("API.Schema.MangaContext.MangaConnectors.MangaConnector"); + b.HasBaseType("API.MangaConnectors.MangaConnector"); b.HasDiscriminator().HasValue("MangaDex"); }); @@ -445,39 +441,23 @@ namespace API.Migrations.Manga modelBuilder.Entity("API.Schema.MangaContext.MangaConnectorId", b => { - b.HasOne("API.Schema.MangaContext.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - b.HasOne("API.Schema.MangaContext.Chapter", "Obj") .WithMany("MangaConnectorIds") .HasForeignKey("ObjId") .OnDelete(DeleteBehavior.NoAction) .IsRequired(); - b.Navigation("MangaConnector"); - b.Navigation("Obj"); }); modelBuilder.Entity("API.Schema.MangaContext.MangaConnectorId", b => { - b.HasOne("API.Schema.MangaContext.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - b.HasOne("API.Schema.MangaContext.Manga", "Obj") .WithMany("MangaConnectorIds") .HasForeignKey("ObjId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("MangaConnector"); - b.Navigation("Obj"); }); diff --git a/API/Migrations/Manga/20250703192023_Initial.cs b/API/Migrations/Manga/20250721093858_Initial.cs similarity index 92% rename from API/Migrations/Manga/20250703192023_Initial.cs rename to API/Migrations/Manga/20250721093858_Initial.cs index cb0a7e7..5983967 100644 --- a/API/Migrations/Manga/20250703192023_Initial.cs +++ b/API/Migrations/Manga/20250721093858_Initial.cs @@ -36,7 +36,7 @@ namespace API.Migrations.Manga }); migrationBuilder.CreateTable( - name: "MangaConnectors", + name: "MangaConnector", columns: table => new { Name = table.Column(type: "character varying(32)", maxLength: 32, nullable: false), @@ -47,7 +47,7 @@ namespace API.Migrations.Manga }, constraints: table => { - table.PrimaryKey("PK_MangaConnectors", x => x.Name); + table.PrimaryKey("PK_MangaConnector", x => x.Name); }); migrationBuilder.CreateTable( @@ -201,12 +201,6 @@ namespace API.Migrations.Manga constraints: table => { table.PrimaryKey("PK_MangaConnectorToManga", x => x.Key); - table.ForeignKey( - name: "FK_MangaConnectorToManga_MangaConnectors_MangaConnectorName", - column: x => x.MangaConnectorName, - principalTable: "MangaConnectors", - principalColumn: "Name", - onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_MangaConnectorToManga_Mangas_ObjId", column: x => x.ObjId, @@ -283,12 +277,6 @@ namespace API.Migrations.Manga column: x => x.ObjId, principalTable: "Chapters", principalColumn: "Key"); - table.ForeignKey( - name: "FK_MangaConnectorToChapter_MangaConnectors_MangaConnectorName", - column: x => x.MangaConnectorName, - principalTable: "MangaConnectors", - principalColumn: "Name", - onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( @@ -311,21 +299,11 @@ namespace API.Migrations.Manga table: "Link", column: "MangaKey"); - migrationBuilder.CreateIndex( - name: "IX_MangaConnectorToChapter_MangaConnectorName", - table: "MangaConnectorToChapter", - column: "MangaConnectorName"); - migrationBuilder.CreateIndex( name: "IX_MangaConnectorToChapter_ObjId", table: "MangaConnectorToChapter", column: "ObjId"); - migrationBuilder.CreateIndex( - name: "IX_MangaConnectorToManga_MangaConnectorName", - table: "MangaConnectorToManga", - column: "MangaConnectorName"); - migrationBuilder.CreateIndex( name: "IX_MangaConnectorToManga_ObjId", table: "MangaConnectorToManga", @@ -359,6 +337,9 @@ namespace API.Migrations.Manga migrationBuilder.DropTable( name: "Link"); + migrationBuilder.DropTable( + name: "MangaConnector"); + migrationBuilder.DropTable( name: "MangaConnectorToChapter"); @@ -377,9 +358,6 @@ namespace API.Migrations.Manga migrationBuilder.DropTable( name: "Chapters"); - migrationBuilder.DropTable( - name: "MangaConnectors"); - migrationBuilder.DropTable( name: "Tags"); diff --git a/API/Migrations/Manga/MangaContextModelSnapshot.cs b/API/Migrations/Manga/MangaContextModelSnapshot.cs index ddaad3b..a2b0af1 100644 --- a/API/Migrations/Manga/MangaContextModelSnapshot.cs +++ b/API/Migrations/Manga/MangaContextModelSnapshot.cs @@ -21,6 +21,39 @@ namespace API.Migrations.Manga NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("API.MangaConnectors.MangaConnector", b => + { + b.Property("Name") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.PrimitiveCollection("BaseUris") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("text[]"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("IconUrl") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.PrimitiveCollection("SupportedLanguages") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("text[]"); + + b.HasKey("Name"); + + b.ToTable("MangaConnector"); + + b.HasDiscriminator("Name").HasValue("MangaConnector"); + + b.UseTphMappingStrategy(); + }); + modelBuilder.Entity("API.Schema.MangaContext.Author", b => { b.Property("Key") @@ -174,8 +207,6 @@ namespace API.Migrations.Manga b.HasKey("Key"); - b.HasIndex("MangaConnectorName"); - b.HasIndex("ObjId"); b.ToTable("MangaConnectorToChapter"); @@ -210,46 +241,11 @@ namespace API.Migrations.Manga b.HasKey("Key"); - b.HasIndex("MangaConnectorName"); - b.HasIndex("ObjId"); b.ToTable("MangaConnectorToManga"); }); - modelBuilder.Entity("API.Schema.MangaContext.MangaConnectors.MangaConnector", b => - { - b.Property("Name") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.PrimitiveCollection("BaseUris") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("text[]"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("IconUrl") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("character varying(2048)"); - - b.PrimitiveCollection("SupportedLanguages") - .IsRequired() - .HasMaxLength(8) - .HasColumnType("text[]"); - - b.HasKey("Name"); - - b.ToTable("MangaConnectors"); - - b.HasDiscriminator("Name").HasValue("MangaConnector"); - - b.UseTphMappingStrategy(); - }); - modelBuilder.Entity("API.Schema.MangaContext.MangaTag", b => { b.Property("Tag") @@ -329,23 +325,23 @@ namespace API.Migrations.Manga b.ToTable("MangaTagToManga"); }); - modelBuilder.Entity("API.Schema.MangaContext.MangaConnectors.ComickIo", b => + modelBuilder.Entity("API.MangaConnectors.ComickIo", b => { - b.HasBaseType("API.Schema.MangaContext.MangaConnectors.MangaConnector"); + b.HasBaseType("API.MangaConnectors.MangaConnector"); b.HasDiscriminator().HasValue("ComickIo"); }); - modelBuilder.Entity("API.Schema.MangaContext.MangaConnectors.Global", b => + modelBuilder.Entity("API.MangaConnectors.Global", b => { - b.HasBaseType("API.Schema.MangaContext.MangaConnectors.MangaConnector"); + b.HasBaseType("API.MangaConnectors.MangaConnector"); b.HasDiscriminator().HasValue("Global"); }); - modelBuilder.Entity("API.Schema.MangaContext.MangaConnectors.MangaDex", b => + modelBuilder.Entity("API.MangaConnectors.MangaDex", b => { - b.HasBaseType("API.Schema.MangaContext.MangaConnectors.MangaConnector"); + b.HasBaseType("API.MangaConnectors.MangaConnector"); b.HasDiscriminator().HasValue("MangaDex"); }); @@ -442,39 +438,23 @@ namespace API.Migrations.Manga modelBuilder.Entity("API.Schema.MangaContext.MangaConnectorId", b => { - b.HasOne("API.Schema.MangaContext.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - b.HasOne("API.Schema.MangaContext.Chapter", "Obj") .WithMany("MangaConnectorIds") .HasForeignKey("ObjId") .OnDelete(DeleteBehavior.NoAction) .IsRequired(); - b.Navigation("MangaConnector"); - b.Navigation("Obj"); }); modelBuilder.Entity("API.Schema.MangaContext.MangaConnectorId", b => { - b.HasOne("API.Schema.MangaContext.MangaConnectors.MangaConnector", "MangaConnector") - .WithMany() - .HasForeignKey("MangaConnectorName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - b.HasOne("API.Schema.MangaContext.Manga", "Obj") .WithMany("MangaConnectorIds") .HasForeignKey("ObjId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("MangaConnector"); - b.Navigation("Obj"); }); diff --git a/API/Program.cs b/API/Program.cs index c507d4b..8a4301d 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -1,8 +1,8 @@ using System.Reflection; using API; +using API.MangaConnectors; using API.Schema.LibraryContext; using API.Schema.MangaContext; -using API.Schema.MangaContext.MangaConnectors; using API.Schema.NotificationsContext; using Asp.Versioning; using Asp.Versioning.Builder; @@ -109,14 +109,6 @@ using (IServiceScope scope = app.Services.CreateScope()) MangaContext context = scope.ServiceProvider.GetRequiredService(); context.Database.Migrate(); - MangaConnector[] connectors = - [ - new MangaDex(), - new ComickIo(), - new Global(scope.ServiceProvider.GetService()!) - ]; - MangaConnector[] newConnectors = connectors.Where(c => !context.MangaConnectors.Contains(c)).ToArray(); - context.MangaConnectors.AddRange(newConnectors); if (!context.FileLibraries.Any()) context.FileLibraries.Add(new FileLibrary(Tranga.Settings.DownloadLocation, "Default FileLibrary")); diff --git a/API/Schema/MangaContext/Chapter.cs b/API/Schema/MangaContext/Chapter.cs index b148356..27cc16d 100644 --- a/API/Schema/MangaContext/Chapter.cs +++ b/API/Schema/MangaContext/Chapter.cs @@ -13,30 +13,12 @@ namespace API.Schema.MangaContext; public class Chapter : Identifiable, IComparable { [StringLength(64)] [Required] public string ParentMangaId { get; init; } = null!; - private Manga? _parentManga; - - [JsonIgnore] - public Manga ParentManga - { - get => _lazyLoader.Load(this, ref _parentManga) ?? throw new InvalidOperationException(); - init - { - ParentMangaId = value.Key; - _parentManga = value; - } - } + [JsonIgnore] public Manga ParentManga = null!; [NotMapped] public Dictionary IdsOnMangaConnectors => MangaConnectorIds.ToDictionary(id => id.MangaConnectorName, id => id.IdOnConnectorSite); - - private ICollection>? _mangaConnectorIds; - [JsonIgnore] - public ICollection> MangaConnectorIds - { - get => _lazyLoader.Load(this, ref _mangaConnectorIds) ?? throw new InvalidOperationException(); - init => _mangaConnectorIds = value; - } + [JsonIgnore] public ICollection> MangaConnectorIds = null!; public int? VolumeNumber { get; private set; } [StringLength(10)] [Required] public string ChapterNumber { get; private set; } @@ -48,8 +30,6 @@ public class Chapter : Identifiable, IComparable [Required] public bool Downloaded { get; internal set; } [NotMapped] public string FullArchiveFilePath => Path.Join(ParentManga.FullDirectoryPath, FileName); - private readonly ILazyLoader _lazyLoader = null!; - public Chapter(Manga parentManga, string chapterNumber, int? volumeNumber, string? title = null) : base(TokenGen.CreateToken(typeof(Chapter), parentManga.Key, chapterNumber)) @@ -66,10 +46,9 @@ public class Chapter : Identifiable, IComparable /// /// EF ONLY!!! /// - internal Chapter(ILazyLoader lazyLoader, string key, int? volumeNumber, string chapterNumber, string? title, string fileName, bool downloaded) + internal Chapter(string key, int? volumeNumber, string chapterNumber, string? title, string fileName, bool downloaded) : base(key) { - this._lazyLoader = lazyLoader; this.VolumeNumber = volumeNumber; this.ChapterNumber = chapterNumber; this.Title = title; diff --git a/API/Schema/MangaContext/Manga.cs b/API/Schema/MangaContext/Manga.cs index 77ee7c7..c50e410 100644 --- a/API/Schema/MangaContext/Manga.cs +++ b/API/Schema/MangaContext/Manga.cs @@ -18,17 +18,7 @@ public class Manga : Identifiable [JsonIgnore] [Url] [StringLength(512)] public string CoverUrl { get; internal set; } [Required] public MangaReleaseStatus ReleaseStatus { get; internal set; } [StringLength(64)] public string? LibraryId { get; private set; } - private FileLibrary? _library; - [JsonIgnore] - public FileLibrary? Library - { - get => _lazyLoader.Load(this, ref _library); - set - { - LibraryId = value?.Key; - _library = value; - } - } + [JsonIgnore] public FileLibrary? Library = null!; public ICollection Authors { get; internal set; }= null!; public ICollection MangaTags { get; internal set; }= null!; @@ -45,25 +35,11 @@ public class Manga : Identifiable public string? FullDirectoryPath => Library is not null ? Path.Join(Library.BasePath, DirectoryName) : null; [NotMapped] public ICollection ChapterIds => Chapters.Select(c => c.Key).ToList(); - private ICollection? _chapters; - [JsonIgnore] - public ICollection Chapters - { - get => _lazyLoader.Load(this, ref _chapters) ?? throw new InvalidOperationException(); - init => _chapters = value; - } + [JsonIgnore] public ICollection Chapters = null!; [NotMapped] public Dictionary IdsOnMangaConnectors => MangaConnectorIds.ToDictionary(id => id.MangaConnectorName, id => id.IdOnConnectorSite); - private ICollection>? _mangaConnectorIds; - [JsonIgnore] - public ICollection> MangaConnectorIds - { - get => _lazyLoader.Load(this, ref _mangaConnectorIds) ?? throw new InvalidOperationException(); - private set => _mangaConnectorIds = value; - } - - private readonly ILazyLoader _lazyLoader = null!; + [JsonIgnore] public ICollection> MangaConnectorIds = null!; public Manga(string name, string description, string coverUrl, MangaReleaseStatus releaseStatus, ICollection authors, ICollection mangaTags, ICollection links, ICollection altTitles, @@ -89,12 +65,11 @@ public class Manga : Identifiable /// /// EF ONLY!!! /// - public Manga(ILazyLoader lazyLoader, string key, string name, string description, string coverUrl, + public Manga(string key, string name, string description, string coverUrl, MangaReleaseStatus releaseStatus, string directoryName, float ignoreChaptersBefore, string? libraryId, uint? year, string? originalLanguage) : base(key) { - this._lazyLoader = lazyLoader; this.Name = name; this.Description = description; this.CoverUrl = coverUrl; diff --git a/API/Schema/MangaContext/MangaConnectorId.cs b/API/Schema/MangaContext/MangaConnectorId.cs index 88fe430..43f09c0 100644 --- a/API/Schema/MangaContext/MangaConnectorId.cs +++ b/API/Schema/MangaContext/MangaConnectorId.cs @@ -1,7 +1,6 @@ using System.ComponentModel.DataAnnotations; -using API.Schema.MangaContext.MangaConnectors; +using API.MangaConnectors; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; using Newtonsoft.Json; namespace API.Schema.MangaContext; @@ -10,43 +9,19 @@ namespace API.Schema.MangaContext; public class MangaConnectorId : Identifiable where T : Identifiable { [StringLength(64)] [Required] public string ObjId { get; private set; } = null!; - [JsonIgnore] private T? _obj; - - [JsonIgnore] - public T Obj - { - get => _lazyLoader.Load(this, ref _obj) ?? throw new InvalidOperationException(); - internal set - { - ObjId = value.Key; - _obj = value; - } - } + [JsonIgnore] public T Obj = null!; [StringLength(32)] [Required] public string MangaConnectorName { get; private set; } = null!; - [JsonIgnore] private MangaConnector? _mangaConnector; - [JsonIgnore] - public MangaConnector MangaConnector - { - get => _lazyLoader.Load(this, ref _mangaConnector) ?? throw new InvalidOperationException(); - init - { - MangaConnectorName = value.Name; - _mangaConnector = value; - } - } [StringLength(256)] [Required] public string IdOnConnectorSite { get; init; } [Url] [StringLength(512)] public string? WebsiteUrl { get; internal init; } public bool UseForDownload { get; internal set; } - - private readonly ILazyLoader _lazyLoader = null!; public MangaConnectorId(T obj, MangaConnector mangaConnector, string idOnConnectorSite, string? websiteUrl, bool useForDownload = false) : base(TokenGen.CreateToken(typeof(MangaConnectorId), mangaConnector.Name, idOnConnectorSite)) { this.Obj = obj; - this.MangaConnector = mangaConnector; + this.MangaConnectorName = mangaConnector.Name; this.IdOnConnectorSite = idOnConnectorSite; this.WebsiteUrl = websiteUrl; this.UseForDownload = useForDownload; @@ -55,10 +30,9 @@ public class MangaConnectorId : Identifiable where T : Identifiable /// /// EF CORE ONLY!!! /// - public MangaConnectorId(ILazyLoader lazyLoader, string key, string objId, string mangaConnectorName, string idOnConnectorSite, bool useForDownload, string? websiteUrl) + public MangaConnectorId(string key, string objId, string mangaConnectorName, string idOnConnectorSite, bool useForDownload, string? websiteUrl) : base(key) { - this._lazyLoader = lazyLoader; this.ObjId = objId; this.MangaConnectorName = mangaConnectorName; this.IdOnConnectorSite = idOnConnectorSite; @@ -66,5 +40,5 @@ public class MangaConnectorId : Identifiable where T : Identifiable this.UseForDownload = useForDownload; } - public override string ToString() => $"{base.ToString()} {_obj}"; + public override string ToString() => $"{base.ToString()} {Obj}"; } \ No newline at end of file diff --git a/API/Schema/MangaContext/MangaContext.cs b/API/Schema/MangaContext/MangaContext.cs index 3e8e9e6..fdff5ab 100644 --- a/API/Schema/MangaContext/MangaContext.cs +++ b/API/Schema/MangaContext/MangaContext.cs @@ -1,4 +1,4 @@ -using API.Schema.MangaContext.MangaConnectors; +using API.MangaConnectors; using API.Schema.MangaContext.MetadataFetchers; using Microsoft.EntityFrameworkCore; @@ -6,7 +6,6 @@ namespace API.Schema.MangaContext; public class MangaContext(DbContextOptions options) : TrangaBaseContext(options) { - public DbSet MangaConnectors { get; set; } public DbSet Mangas { get; set; } public DbSet FileLibraries { get; set; } public DbSet Chapters { get; set; } @@ -31,26 +30,12 @@ public class MangaContext(DbContextOptions options) : TrangaBaseCo .WithOne(c => c.ParentManga) .HasForeignKey(c => c.ParentMangaId) .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(m => m.Chapters) - .EnableLazyLoading(); - modelBuilder.Entity() - .Navigation(c => c.ParentManga) - .EnableLazyLoading(); //Chapter has MangaConnectorIds modelBuilder.Entity() .HasMany>(c => c.MangaConnectorIds) .WithOne(id => id.Obj) .HasForeignKey(id => id.ObjId) .OnDelete(DeleteBehavior.NoAction); - modelBuilder.Entity>() - .HasOne(id => id.MangaConnector) - .WithMany() - .HasForeignKey(id => id.MangaConnectorName) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity>() - .Navigation(entry => entry.MangaConnector) - .EnableLazyLoading(); //Manga owns MangaAltTitles modelBuilder.Entity() .OwnsMany(m => m.AltTitles) @@ -95,17 +80,6 @@ public class MangaContext(DbContextOptions options) : TrangaBaseCo .WithOne(id => id.Obj) .HasForeignKey(id => id.ObjId) .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity() - .Navigation(m => m.MangaConnectorIds) - .EnableLazyLoading(); - modelBuilder.Entity>() - .HasOne(id => id.MangaConnector) - .WithMany() - .HasForeignKey(id => id.MangaConnectorName) - .OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity>() - .Navigation(entry => entry.MangaConnector) - .EnableLazyLoading(); //FileLibrary has many Mangas @@ -114,9 +88,6 @@ public class MangaContext(DbContextOptions options) : TrangaBaseCo .WithOne(m => m.Library) .HasForeignKey(m => m.LibraryId) .OnDelete(DeleteBehavior.SetNull); - modelBuilder.Entity() - .Navigation(m => m.Library) - .EnableLazyLoading(); modelBuilder.Entity() .HasDiscriminator(nameof(MetadataEntry)) diff --git a/API/Tranga.cs b/API/Tranga.cs index 65d27fc..c299ecd 100644 --- a/API/Tranga.cs +++ b/API/Tranga.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using API.MangaConnectors; using API.Schema.LibraryContext; using API.Schema.MangaContext; using API.Schema.MangaContext.MetadataFetchers; @@ -25,6 +26,7 @@ public static class Tranga public static Thread PeriodicWorkerStarterThread { get; } = new (WorkerStarter); private static readonly ILog Log = LogManager.GetLogger(typeof(Tranga)); internal static readonly MetadataFetcher[] MetadataFetchers = [new MyAnimeList()]; + internal static readonly MangaConnector[] MangaConnectors = [new Global(), new MangaDex(), new ComickIo()]; internal static TrangaSettings Settings = TrangaSettings.Load(); internal static readonly UpdateMetadataWorker UpdateMetadataWorker = new (); @@ -52,6 +54,13 @@ public static class Tranga AddWorker(StartNewChapterDownloadsWorker); AddWorker(RemoveOldNotificationsWorker); } + + internal static bool TryGetMangaConnector(string name, [NotNullWhen(true)]out MangaConnector? mangaConnector) + { + mangaConnector = + MangaConnectors.FirstOrDefault(c => c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)); + return mangaConnector != null; + } internal static HashSet AllWorkers { get; private set; } = new (); diff --git a/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs b/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs index 0328def..64d39ff 100644 --- a/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs +++ b/API/Workers/MangaDownloadWorkers/DownloadChapterFromMangaconnectorWorker.cs @@ -1,8 +1,8 @@ using System.IO.Compression; using System.Runtime.InteropServices; +using API.MangaConnectors; using API.MangaDownloadClients; using API.Schema.MangaContext; -using API.Schema.MangaContext.MangaConnectors; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Processing; @@ -17,17 +17,18 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c internal readonly string MangaConnectorIdId = chId.Key; protected override BaseWorker[] DoWorkInternal() { - if (DbContext.MangaConnectorToChapter.Find(MangaConnectorIdId) is not { } MangaConnectorId) + if (DbContext.MangaConnectorToChapter.Find(MangaConnectorIdId) is not { } mangaConnectorId) return []; //TODO Exception? - MangaConnector mangaConnector = MangaConnectorId.MangaConnector; - Chapter chapter = MangaConnectorId.Obj; + if (!Tranga.TryGetMangaConnector(mangaConnectorId.MangaConnectorName, out MangaConnector? mangaConnector)) + return []; //TODO Exception? + Chapter chapter = mangaConnectorId.Obj; if (chapter.Downloaded) { Log.Info("Chapter was already downloaded."); return []; } - string[] imageUrls = mangaConnector.GetChapterImageUrls(MangaConnectorId); + string[] imageUrls = mangaConnector.GetChapterImageUrls(mangaConnectorId); if (imageUrls.Length < 1) { Log.Info($"No imageUrls for chapter {chapter}"); @@ -147,10 +148,15 @@ public class DownloadChapterFromMangaconnectorWorker(MangaConnectorId c } //TODO MangaConnector Selection - MangaConnectorId mcId = manga.MangaConnectorIds.First(); + MangaConnectorId mangaConnectorId = manga.MangaConnectorIds.First(); + if (!Tranga.TryGetMangaConnector(mangaConnectorId.MangaConnectorName, out MangaConnector? mangaConnector)) + { + Log.Error($"MangaConnector with name {mangaConnectorId.MangaConnectorName} could not be found"); + return; + } Log.Info($"Copying cover to {publicationFolder}"); - string? fileInCache = manga.CoverFileNameInCache ?? mcId.MangaConnector.SaveCoverImageToCache(mcId); + string? fileInCache = manga.CoverFileNameInCache ?? mangaConnector.SaveCoverImageToCache(mangaConnectorId); if (fileInCache is null) { Log.Error($"File {fileInCache} does not exist"); diff --git a/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs b/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs index ba07613..bdae3e2 100644 --- a/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs +++ b/API/Workers/MangaDownloadWorkers/DownloadCoverFromMangaconnectorWorker.cs @@ -1,5 +1,5 @@ +using API.MangaConnectors; using API.Schema.MangaContext; -using API.Schema.MangaContext.MangaConnectors; namespace API.Workers; @@ -9,12 +9,13 @@ public class DownloadCoverFromMangaconnectorWorker(MangaConnectorId mcId, internal readonly string MangaConnectorIdId = mcId.Key; protected override BaseWorker[] DoWorkInternal() { - if (DbContext.MangaConnectorToManga.Find(MangaConnectorIdId) is not { } MangaConnectorId) + if (DbContext.MangaConnectorToManga.Find(MangaConnectorIdId) is not { } mangaConnectorId) return []; //TODO Exception? - MangaConnector mangaConnector = MangaConnectorId.MangaConnector; - Manga manga = MangaConnectorId.Obj; + if (!Tranga.TryGetMangaConnector(mangaConnectorId.MangaConnectorName, out MangaConnector? mangaConnector)) + return []; //TODO Exception? + Manga manga = mangaConnectorId.Obj; - manga.CoverFileNameInCache = mangaConnector.SaveCoverImageToCache(MangaConnectorId); + manga.CoverFileNameInCache = mangaConnector.SaveCoverImageToCache(mangaConnectorId); DbContext.Sync(); return []; diff --git a/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs b/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs index ec03b95..65c462b 100644 --- a/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs +++ b/API/Workers/MangaDownloadWorkers/RetrieveMangaChaptersFromMangaconnectorWorker.cs @@ -1,5 +1,5 @@ +using API.MangaConnectors; using API.Schema.MangaContext; -using API.Schema.MangaContext.MangaConnectors; namespace API.Workers; @@ -9,13 +9,14 @@ public class RetrieveMangaChaptersFromMangaconnectorWorker(MangaConnectorId)[] allChapters = - mangaConnector.GetChapters(MangaConnectorId, language).DistinctBy(c => c.Item1.Key).ToArray(); + mangaConnector.GetChapters(mangaConnectorId, language).DistinctBy(c => c.Item1.Key).ToArray(); int addedChapters = 0; foreach ((Chapter chapter, MangaConnectorId mcId) newChapter in allChapters) diff --git a/API/Workers/PeriodicWorkers/StartNewChapterDownloadsWorker.cs b/API/Workers/PeriodicWorkers/StartNewChapterDownloadsWorker.cs index 438e178..20872e5 100644 --- a/API/Workers/PeriodicWorkers/StartNewChapterDownloadsWorker.cs +++ b/API/Workers/PeriodicWorkers/StartNewChapterDownloadsWorker.cs @@ -1,4 +1,5 @@ using API.Schema.MangaContext; +using Microsoft.EntityFrameworkCore; namespace API.Workers; @@ -10,7 +11,9 @@ public class StartNewChapterDownloadsWorker(TimeSpan? interval = null, IEnumerab public TimeSpan Interval { get; set; } = interval ?? TimeSpan.FromMinutes(1); protected override BaseWorker[] DoWorkInternal() { - IQueryable> mangaConnectorIds = DbContext.MangaConnectorToChapter.Where(id => id.Obj.Downloaded == false && id.UseForDownload); + IQueryable> mangaConnectorIds = DbContext.MangaConnectorToChapter + .Include(id => id.Obj) + .Where(id => id.Obj.Downloaded == false && id.UseForDownload); List newWorkers = new(); foreach (MangaConnectorId mangaConnectorId in mangaConnectorIds)