diff --git a/API/Controllers/MangaController.cs b/API/Controllers/MangaController.cs index 7bbcf00..a42c975 100644 --- a/API/Controllers/MangaController.cs +++ b/API/Controllers/MangaController.cs @@ -41,15 +41,7 @@ public class MangaController(MangaContext context) : Controller [ProducesResponseType(Status200OK, "application/json")] public IActionResult GetManga([FromBody]string[] MangaIds) { - Manga[] ret = context.Mangas.Where(m => MangaIds.Contains(m.Key)) - .Include(m => m.Library) - .Include(m => m.Authors) - .Include(m => m.MangaTags) - .Include(m => m.Links) - .Include(m => m.AltTitles) - .Include(m => m.Chapters) - .Include(m => m.MangaConnectorIds) - .ToArray(); + Manga[] ret = context.MangaIncludeAll().Where(m => MangaIds.Contains(m.Key)).ToArray(); return Ok(ret); } @@ -64,11 +56,8 @@ public class MangaController(MangaContext context) : Controller [ProducesResponseType(Status404NotFound)] public IActionResult GetManga(string MangaId) { - if (context.Mangas.Find(MangaId) is not { } manga) + if (context.MangaIncludeAll().FirstOrDefault(m => m.Key == MangaId) is not { } manga) return NotFound(nameof(MangaId)); - foreach (CollectionEntry collectionEntry in context.Entry(manga).Collections) - collectionEntry.Load(); - context.Entry(manga).Navigation(nameof(Manga.Library)).Load(); return Ok(manga); } diff --git a/API/MangaConnectors/ComickIo.cs b/API/MangaConnectors/ComickIo.cs index b5829b6..ec9a55f 100644 --- a/API/MangaConnectors/ComickIo.cs +++ b/API/MangaConnectors/ComickIo.cs @@ -177,19 +177,19 @@ public class ComickIo : MangaConnector byte whatever = 0; List altTitles = altTitlesArray? .Select(token => new AltTitle(token.Value("lang")??whatever++.ToString(), token.Value("title")!)) - .ToList()!; + .ToList()??[]; JArray? authorsArray = json["authors"] as JArray; JArray? artistsArray = json["artists"] as JArray; List authors = authorsArray?.Concat(artistsArray!) .Select(token => new Author(token.Value("name")!)) .DistinctBy(a => a.Key) - .ToList()!; + .ToList()??[]; JArray? genreArray = json["comic"]?["md_comic_md_genres"] as JArray; List tags = genreArray? .Select(token => new MangaTag(token["md_genres"]?.Value("name")!)) - .ToList()!; + .ToList()??[]; JArray? linksArray = json["comic"]?["links"] as JArray; List links = linksArray? @@ -221,7 +221,7 @@ public class ComickIo : MangaConnector _ => kv.Key }; return new Link(key, fullUrl); - }).ToList()!; + }).ToList()??[]; if(hid is null) throw new Exception("hid is null"); @@ -232,7 +232,9 @@ public class ComickIo : MangaConnector Manga manga = new (name, description??"", coverUrl, status, authors, tags, links, altTitles, year: year, originalLanguage: originalLanguage); - return (manga, new MangaConnectorId(manga, this, hid, url)); + MangaConnectorId mcId = new (manga, this, hid, url); + manga.MangaConnectorIds.Add(mcId); + return (manga, mcId); } private List<(Chapter, MangaConnectorId)> ParseChapters(MangaConnectorId mcIdManga, JArray chaptersArray) @@ -251,8 +253,9 @@ public class ComickIo : MangaConnector continue; Chapter ch = new (mcIdManga.Obj, chapterNum, volumeNum, title); - - chapters.Add((ch, new (ch, this, hid, url))); + MangaConnectorId mcId = new(ch, this, hid, url); + ch.MangaConnectorIds.Add(mcId); + chapters.Add((ch, mcId)); } return chapters; } diff --git a/API/MangaConnectors/MangaDex.cs b/API/MangaConnectors/MangaDex.cs index ba10e45..cc78dfe 100644 --- a/API/MangaConnectors/MangaDex.cs +++ b/API/MangaConnectors/MangaDex.cs @@ -313,9 +313,11 @@ public class MangaDex : MangaConnector string websiteUrl = $"https://mangadex.org/title/{id}"; string coverUrl = $"https://uploads.mangadex.org/covers/{id}/{coverFileName}"; - Manga manga = new Manga(name, description, coverUrl, releaseStatus, authors, tags, links,altTitles, + Manga manga = new (name, description, coverUrl, releaseStatus, authors, tags, links,altTitles, null, 0f, year, originalLanguage); - return (manga, new MangaConnectorId(manga, this, id, websiteUrl)); + MangaConnectorId mcId = new (manga, this, id, websiteUrl); + manga.MangaConnectorIds.Add(mcId); + return (manga, mcId); } private (Chapter chapter, MangaConnectorId id) ParseChapterFromJToken(MangaConnectorId mcIdManga, JToken jToken) @@ -334,6 +336,8 @@ public class MangaDex : MangaConnector string websiteUrl = $"https://mangadex.org/chapter/{id}"; Chapter chapter = new (mcIdManga.Obj, chapterStr, volumeNumber, title); - return (chapter, new MangaConnectorId(chapter, this, id, websiteUrl)); + MangaConnectorId mcId = new(chapter, this, id, websiteUrl); + chapter.MangaConnectorIds.Add(mcId); + return (chapter, mcId); } } \ No newline at end of file diff --git a/API/Schema/MangaContext/Chapter.cs b/API/Schema/MangaContext/Chapter.cs index 1be326b..61663a1 100644 --- a/API/Schema/MangaContext/Chapter.cs +++ b/API/Schema/MangaContext/Chapter.cs @@ -39,6 +39,7 @@ public class Chapter : Identifiable, IComparable this.Title = title; this.FileName = GetArchiveFilePath(); this.Downloaded = false; + this.MangaConnectorIds = []; } /// diff --git a/API/Schema/MangaContext/Manga.cs b/API/Schema/MangaContext/Manga.cs index 99b4b42..b606f16 100644 --- a/API/Schema/MangaContext/Manga.cs +++ b/API/Schema/MangaContext/Manga.cs @@ -61,6 +61,7 @@ public class Manga : Identifiable this.Year = year; this.OriginalLanguage = originalLanguage; this.Chapters = []; + this.MangaConnectorIds = []; } /// diff --git a/API/Schema/MangaContext/MangaConnectorId.cs b/API/Schema/MangaContext/MangaConnectorId.cs index 22797d0..ee1508b 100644 --- a/API/Schema/MangaContext/MangaConnectorId.cs +++ b/API/Schema/MangaContext/MangaConnectorId.cs @@ -8,7 +8,7 @@ namespace API.Schema.MangaContext; [PrimaryKey("Key")] public class MangaConnectorId : Identifiable where T : Identifiable { - [StringLength(64)] [Required] public string ObjId { get; private set; } + [StringLength(64)] [Required] public string ObjId { get; internal set; } [JsonIgnore] public T Obj = null!; [StringLength(32)] [Required] public string MangaConnectorName { get; private set; } diff --git a/API/Schema/MangaContext/MangaContext.cs b/API/Schema/MangaContext/MangaContext.cs index fdff5ab..4d4d952 100644 --- a/API/Schema/MangaContext/MangaContext.cs +++ b/API/Schema/MangaContext/MangaContext.cs @@ -1,6 +1,7 @@ using API.MangaConnectors; using API.Schema.MangaContext.MetadataFetchers; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; namespace API.Schema.MangaContext; @@ -102,4 +103,23 @@ public class MangaContext(DbContextOptions options) : TrangaBaseCo .WithMany() .OnDelete(DeleteBehavior.Cascade); } + + public Manga? FindMangaLike(Manga other) + { + if (MangaIncludeAll().FirstOrDefault(m => m.Key == other.Key) 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)))); + } + + public IIncludableQueryable>> MangaIncludeAll() => Mangas.Include(m => m.Library) + .Include(m => m.Authors) + .Include(m => m.MangaTags) + .Include(m => m.Links) + .Include(m => m.AltTitles) + .Include(m => m.Chapters) + .Include(m => m.MangaConnectorIds); } \ No newline at end of file diff --git a/API/Tranga.cs b/API/Tranga.cs index fa34cc4..a2500d7 100644 --- a/API/Tranga.cs +++ b/API/Tranga.cs @@ -9,7 +9,7 @@ using API.Workers; using API.Workers.MaintenanceWorkers; using log4net; using log4net.Config; -using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore; namespace API; @@ -162,30 +162,41 @@ public static class Tranga internal static bool AddMangaToContext(Manga addManga, MangaConnectorId addMcId, MangaContext context, [NotNullWhen(true)]out Manga? manga) { - manga = context.Mangas.Find(addManga.Key) ?? addManga; - MangaConnectorId mcId = context.MangaConnectorToManga.Find(addMcId.Key) ?? addMcId; - mcId.Obj = manga; - - foreach (CollectionEntry collectionEntry in context.Entry(manga).Collections) - collectionEntry.Load(); - context.Entry(manga).Navigation(nameof(Manga.Library)).Load(); - - IEnumerable mergedTags = manga.MangaTags.Select(mt => + context.ChangeTracker.Clear(); + manga = context.FindMangaLike(addManga); + if (manga is not null) { - MangaTag? inDb = context.Tags.Find(mt.Tag); - return inDb ?? mt; - }); - manga.MangaTags = mergedTags.ToList(); + foreach (MangaConnectorId mcId in addManga.MangaConnectorIds) + { + mcId.Obj = manga; + mcId.ObjId = manga.Key; + } + manga.MangaTags = manga.MangaTags.UnionBy(addManga.MangaTags, tag => tag.Tag).ToList(); + manga.Authors = manga.Authors.UnionBy(addManga.Authors, author => author.Key).ToList(); + manga.Links = manga.Links.UnionBy(addManga.Links, link => link.Key).ToList(); + manga.AltTitles = manga.AltTitles.UnionBy(addManga.AltTitles, altTitle => altTitle.Key).ToList(); + manga.Chapters = manga.Chapters.UnionBy(addManga.Chapters, chapter => chapter.Key).ToList(); + manga.MangaConnectorIds = manga.MangaConnectorIds.UnionBy(addManga.MangaConnectorIds, id => id.MangaConnectorName).ToList(); + } + else + { + manga = addManga; + IEnumerable mergedTags = manga.MangaTags.Select(mt => + { + MangaTag? inDb = context.Tags.Find(mt.Tag); + return inDb ?? mt; + }); + manga.MangaTags = mergedTags.ToList(); - IEnumerable mergedAuthors = manga.Authors.Select(ma => - { - Author? inDb = context.Authors.Find(ma.Key); - return inDb ?? ma; - }); - manga.Authors = mergedAuthors.ToList(); - - if(context.MangaConnectorToManga.Find(addMcId.Key) is null) - context.MangaConnectorToManga.Add(mcId); + IEnumerable mergedAuthors = manga.Authors.Select(ma => + { + Author? inDb = context.Authors.Find(ma.Key); + return inDb ?? ma; + }); + manga.Authors = mergedAuthors.ToList(); + + context.Mangas.Add(manga); + } if (context.Sync() is { success: false }) return false; @@ -201,16 +212,19 @@ public static class Tranga internal static bool AddChapterToContext(Chapter addChapter, MangaConnectorId addChId, MangaContext context, [NotNullWhen(true)] out Chapter? chapter) { - chapter = context.Chapters.Find(addChapter.Key) ?? addChapter; - MangaConnectorId chId = context.MangaConnectorToChapter.Find(addChId.Key) ?? addChId; - chId.Obj = chapter; - - foreach (CollectionEntry collectionEntry in context.Entry(chapter).Collections) - collectionEntry.Load(); - context.Entry(chapter).Navigation(nameof(Chapter.ParentManga)).Load(); - - if(context.MangaConnectorToChapter.Find(chId.Key) is null) - context.MangaConnectorToChapter.Add(chId); + chapter = context.Chapters.Where(ch => ch.Key == addChapter.Key) + .Include(ch => ch.ParentManga) + .Include(ch => ch.MangaConnectorIds) + .FirstOrDefault(); + if (chapter is not null) + { + chapter.MangaConnectorIds = chapter.MangaConnectorIds.UnionBy(addChapter.MangaConnectorIds, id => id.Key).ToList(); + } + else + { + context.Chapters.Add(addChapter); + chapter = addChapter; + } if (context.Sync() is { success: false }) return false;