WIP: Manga can be linked to multiple Connectors

- PgsqlContext Adjustment
This commit is contained in:
2025-06-30 14:42:24 +02:00
parent e9d9bebcd7
commit ea73d03b8f
4 changed files with 49 additions and 31 deletions

View File

@ -15,7 +15,21 @@ public class Chapter : IComparable<Chapter>
[StringLength(64)] [Required] public string ChapterId { get; init; } [StringLength(64)] [Required] public string ChapterId { get; init; }
[StringLength(256)]public string? IdOnConnectorSite { get; init; } [StringLength(256)]public string? IdOnConnectorSite { get; init; }
[StringLength(64)] [Required] public string ParentMangaId { get; init; } = null!;
private Manga? _parentManga = null!;
[JsonIgnore]
public Manga ParentManga
{
get => _lazyLoader.Load(this, ref _parentManga) ?? throw new InvalidOperationException();
init
{
ParentMangaId = value.MangaId;
_parentManga = value;
}
}
private MangaConnectorMangaEntry? _mangaConnectorMangaEntry = null!; private MangaConnectorMangaEntry? _mangaConnectorMangaEntry = null!;
[JsonIgnore] [JsonIgnore]
public MangaConnectorMangaEntry MangaConnectorMangaEntry public MangaConnectorMangaEntry MangaConnectorMangaEntry

View File

@ -40,31 +40,40 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
.HasValue<RetrieveChaptersJob>(JobType.RetrieveChaptersJob) .HasValue<RetrieveChaptersJob>(JobType.RetrieveChaptersJob)
.HasValue<UpdateCoverJob>(JobType.UpdateCoverJob) .HasValue<UpdateCoverJob>(JobType.UpdateCoverJob)
.HasValue<UpdateChaptersDownloadedJob>(JobType.UpdateChaptersDownloadedJob); .HasValue<UpdateChaptersDownloadedJob>(JobType.UpdateChaptersDownloadedJob);
modelBuilder.Entity<Job>()
.HasDiscriminator(j => j.GetType().IsSubclassOf(typeof(JobWithDownloading)))
.HasValue<JobWithDownloading>(true);
//Job specification //Job specification
modelBuilder.Entity<DownloadAvailableChaptersJob>() modelBuilder.Entity<JobWithDownloading>()
.HasOne<Manga>(j => j.Manga) .HasOne<MangaConnector>(j => j.MangaConnector)
.WithMany()
.HasForeignKey(j => j.MangaConnectorName)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<JobWithDownloading>()
.Navigation(j => j.MangaConnector)
.EnableLazyLoading();
modelBuilder.Entity<DownloadAvailableChaptersJob>()
.HasOne<MangaConnectorMangaEntry>(j => j.MangaConnectorMangaEntry)
.WithMany() .WithMany()
.HasForeignKey(j => j.MangaId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<DownloadAvailableChaptersJob>() modelBuilder.Entity<DownloadAvailableChaptersJob>()
.Navigation(j => j.Manga) .Navigation(j => j.MangaConnectorMangaEntry)
.EnableLazyLoading(); .EnableLazyLoading();
modelBuilder.Entity<DownloadMangaCoverJob>() modelBuilder.Entity<DownloadMangaCoverJob>()
.HasOne<Manga>(j => j.Manga) .HasOne<MangaConnectorMangaEntry>(j => j.MangaConnectorMangaEntry)
.WithMany() .WithMany()
.HasForeignKey(j => j.MangaId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<DownloadMangaCoverJob>() modelBuilder.Entity<DownloadMangaCoverJob>()
.Navigation(j => j.Manga) .Navigation(j => j.MangaConnectorMangaEntry)
.EnableLazyLoading(); .EnableLazyLoading();
modelBuilder.Entity<DownloadSingleChapterJob>() modelBuilder.Entity<DownloadSingleChapterJob>()
.HasOne<Chapter>(j => j.Chapter) .HasOne<MangaConnectorMangaEntry>(j => j.MangaConnectorMangaEntry)
.WithMany() .WithMany()
.HasForeignKey(j => j.ChapterId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<DownloadSingleChapterJob>() modelBuilder.Entity<DownloadSingleChapterJob>()
.Navigation(j => j.Chapter) .Navigation(j => j.MangaConnectorMangaEntry)
.EnableLazyLoading(); .EnableLazyLoading();
modelBuilder.Entity<MoveMangaLibraryJob>() modelBuilder.Entity<MoveMangaLibraryJob>()
.HasOne<Manga>(j => j.Manga) .HasOne<Manga>(j => j.Manga)
@ -83,12 +92,11 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
.Navigation(j => j.ToLibrary) .Navigation(j => j.ToLibrary)
.EnableLazyLoading(); .EnableLazyLoading();
modelBuilder.Entity<RetrieveChaptersJob>() modelBuilder.Entity<RetrieveChaptersJob>()
.HasOne<Manga>(j => j.Manga) .HasOne<MangaConnectorMangaEntry>(j => j.MangaConnectorMangaEntry)
.WithMany() .WithMany()
.HasForeignKey(j => j.MangaId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<RetrieveChaptersJob>() modelBuilder.Entity<RetrieveChaptersJob>()
.Navigation(j => j.Manga) .Navigation(j => j.MangaConnectorMangaEntry)
.EnableLazyLoading(); .EnableLazyLoading();
modelBuilder.Entity<UpdateChaptersDownloadedJob>() modelBuilder.Entity<UpdateChaptersDownloadedJob>()
.HasOne<Manga>(j => j.Manga) .HasOne<Manga>(j => j.Manga)
@ -120,15 +128,6 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
.HasValue<Global>("Global") .HasValue<Global>("Global")
.HasValue<MangaDex>("MangaDex") .HasValue<MangaDex>("MangaDex")
.HasValue<ComickIo>("ComickIo"); .HasValue<ComickIo>("ComickIo");
//MangaConnector is responsible for many Manga
modelBuilder.Entity<MangaConnector>()
.HasMany<Manga>()
.WithOne(m => m.MangaConnector)
.HasForeignKey(m => m.MangaConnectorName)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Manga>()
.Navigation(m => m.MangaConnector)
.AutoInclude();
//Manga has many Chapters //Manga has many Chapters
modelBuilder.Entity<Manga>() modelBuilder.Entity<Manga>()
@ -136,9 +135,6 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
.WithOne(c => c.ParentManga) .WithOne(c => c.ParentManga)
.HasForeignKey(c => c.ParentMangaId) .HasForeignKey(c => c.ParentMangaId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Chapter>()
.Navigation(c => c.ParentManga)
.AutoInclude();
modelBuilder.Entity<Manga>() modelBuilder.Entity<Manga>()
.Navigation(m => m.Chapters) .Navigation(m => m.Chapters)
.AutoInclude(false) .AutoInclude(false)
@ -181,6 +177,17 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
modelBuilder.Entity<Manga>() modelBuilder.Entity<Manga>()
.Navigation(m => m.Authors) .Navigation(m => m.Authors)
.AutoInclude(); .AutoInclude();
//Manga has many MangaConnectorMangaEntries with one MangaConnector
modelBuilder.Entity<Manga>()
.HasMany<MangaConnectorMangaEntry>(m => m.MangaConnectorLinkedToManga)
.WithOne(e => e.Manga)
.HasForeignKey(e => e.MangaId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<MangaConnectorMangaEntry>()
.HasOne<MangaConnector>(e => e.MangaConnector)
.WithMany()
.HasForeignKey(e => e.MangaConnectorName)
.OnDelete(DeleteBehavior.Cascade);
//LocalLibrary has many Mangas //LocalLibrary has many Mangas
modelBuilder.Entity<LocalLibrary>() modelBuilder.Entity<LocalLibrary>()

View File

@ -37,7 +37,7 @@ public class RetrieveChaptersJob : JobWithDownloading
protected override IEnumerable<Job> RunInternal(PgsqlContext context) protected override IEnumerable<Job> RunInternal(PgsqlContext context)
{ {
// This gets all chapters that are not downloaded // This gets all chapters that are not downloaded
Chapter[] allChapters = MangaConnectorMangaEntry.MangaConnector.GetChapters(MangaConnectorMangaEntry.Manga, Language).DistinctBy(c => c.ChapterId).ToArray(); Chapter[] allChapters = MangaConnectorMangaEntry.MangaConnector.GetChapters(MangaConnectorMangaEntry, Language).DistinctBy(c => c.ChapterId).ToArray();
Chapter[] newChapters = allChapters.Where(chapter => MangaConnectorMangaEntry.Manga.Chapters.Select(c => c.ChapterId).Contains(chapter.ChapterId) == false).ToArray(); Chapter[] newChapters = allChapters.Where(chapter => MangaConnectorMangaEntry.Manga.Chapters.Select(c => c.ChapterId).Contains(chapter.ChapterId) == false).ToArray();
Log.Info($"{MangaConnectorMangaEntry.Manga.Chapters.Count} existing + {newChapters.Length} new chapters."); Log.Info($"{MangaConnectorMangaEntry.Manga.Chapters.Count} existing + {newChapters.Length} new chapters.");

View File

@ -2,7 +2,6 @@ using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using API.Schema.MangaConnectors;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -13,9 +12,7 @@ namespace API.Schema;
[PrimaryKey("MangaId")] [PrimaryKey("MangaId")]
public class Manga public class Manga
{ {
[StringLength(64)] [StringLength(64)] [Required] public string MangaId { get; init; }
[Required]
public string MangaId { get; init; }
[StringLength(512)] [Required] public string Name { get; internal set; } [StringLength(512)] [Required] public string Name { get; internal set; }
[Required] public string Description { get; internal set; } [Required] public string Description { get; internal set; }
[JsonIgnore] [Url] [StringLength(512)] public string CoverUrl { get; internal set; } [JsonIgnore] [Url] [StringLength(512)] public string CoverUrl { get; internal set; }