mirror of
https://github.com/C9Glax/tranga.git
synced 2025-09-10 20:08:19 +02:00
Fix merging of Manga
Fix ComickIo empty lists
This commit is contained in:
@@ -41,15 +41,7 @@ public class MangaController(MangaContext context) : Controller
|
|||||||
[ProducesResponseType<Manga[]>(Status200OK, "application/json")]
|
[ProducesResponseType<Manga[]>(Status200OK, "application/json")]
|
||||||
public IActionResult GetManga([FromBody]string[] MangaIds)
|
public IActionResult GetManga([FromBody]string[] MangaIds)
|
||||||
{
|
{
|
||||||
Manga[] ret = context.Mangas.Where(m => MangaIds.Contains(m.Key))
|
Manga[] ret = context.MangaIncludeAll().Where(m => MangaIds.Contains(m.Key)).ToArray();
|
||||||
.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();
|
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,11 +56,8 @@ public class MangaController(MangaContext context) : Controller
|
|||||||
[ProducesResponseType(Status404NotFound)]
|
[ProducesResponseType(Status404NotFound)]
|
||||||
public IActionResult GetManga(string MangaId)
|
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));
|
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);
|
return Ok(manga);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -177,19 +177,19 @@ public class ComickIo : MangaConnector
|
|||||||
byte whatever = 0;
|
byte whatever = 0;
|
||||||
List<AltTitle> altTitles = altTitlesArray?
|
List<AltTitle> altTitles = altTitlesArray?
|
||||||
.Select(token => new AltTitle(token.Value<string>("lang")??whatever++.ToString(), token.Value<string>("title")!))
|
.Select(token => new AltTitle(token.Value<string>("lang")??whatever++.ToString(), token.Value<string>("title")!))
|
||||||
.ToList()!;
|
.ToList()??[];
|
||||||
|
|
||||||
JArray? authorsArray = json["authors"] as JArray;
|
JArray? authorsArray = json["authors"] as JArray;
|
||||||
JArray? artistsArray = json["artists"] as JArray;
|
JArray? artistsArray = json["artists"] as JArray;
|
||||||
List<Author> authors = authorsArray?.Concat(artistsArray!)
|
List<Author> authors = authorsArray?.Concat(artistsArray!)
|
||||||
.Select(token => new Author(token.Value<string>("name")!))
|
.Select(token => new Author(token.Value<string>("name")!))
|
||||||
.DistinctBy(a => a.Key)
|
.DistinctBy(a => a.Key)
|
||||||
.ToList()!;
|
.ToList()??[];
|
||||||
|
|
||||||
JArray? genreArray = json["comic"]?["md_comic_md_genres"] as JArray;
|
JArray? genreArray = json["comic"]?["md_comic_md_genres"] as JArray;
|
||||||
List<MangaTag> tags = genreArray?
|
List<MangaTag> tags = genreArray?
|
||||||
.Select(token => new MangaTag(token["md_genres"]?.Value<string>("name")!))
|
.Select(token => new MangaTag(token["md_genres"]?.Value<string>("name")!))
|
||||||
.ToList()!;
|
.ToList()??[];
|
||||||
|
|
||||||
JArray? linksArray = json["comic"]?["links"] as JArray;
|
JArray? linksArray = json["comic"]?["links"] as JArray;
|
||||||
List<Link> links = linksArray?
|
List<Link> links = linksArray?
|
||||||
@@ -221,7 +221,7 @@ public class ComickIo : MangaConnector
|
|||||||
_ => kv.Key
|
_ => kv.Key
|
||||||
};
|
};
|
||||||
return new Link(key, fullUrl);
|
return new Link(key, fullUrl);
|
||||||
}).ToList()!;
|
}).ToList()??[];
|
||||||
|
|
||||||
if(hid is null)
|
if(hid is null)
|
||||||
throw new Exception("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,
|
Manga manga = new (name, description??"", coverUrl, status, authors, tags, links, altTitles,
|
||||||
year: year, originalLanguage: originalLanguage);
|
year: year, originalLanguage: originalLanguage);
|
||||||
return (manga, new MangaConnectorId<Manga>(manga, this, hid, url));
|
MangaConnectorId<Manga> mcId = new (manga, this, hid, url);
|
||||||
|
manga.MangaConnectorIds.Add(mcId);
|
||||||
|
return (manga, mcId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<(Chapter, MangaConnectorId<Chapter>)> ParseChapters(MangaConnectorId<Manga> mcIdManga, JArray chaptersArray)
|
private List<(Chapter, MangaConnectorId<Chapter>)> ParseChapters(MangaConnectorId<Manga> mcIdManga, JArray chaptersArray)
|
||||||
@@ -251,8 +253,9 @@ public class ComickIo : MangaConnector
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
Chapter ch = new (mcIdManga.Obj, chapterNum, volumeNum, title);
|
Chapter ch = new (mcIdManga.Obj, chapterNum, volumeNum, title);
|
||||||
|
MangaConnectorId<Chapter> mcId = new(ch, this, hid, url);
|
||||||
chapters.Add((ch, new (ch, this, hid, url)));
|
ch.MangaConnectorIds.Add(mcId);
|
||||||
|
chapters.Add((ch, mcId));
|
||||||
}
|
}
|
||||||
return chapters;
|
return chapters;
|
||||||
}
|
}
|
||||||
|
@@ -313,9 +313,11 @@ public class MangaDex : MangaConnector
|
|||||||
string websiteUrl = $"https://mangadex.org/title/{id}";
|
string websiteUrl = $"https://mangadex.org/title/{id}";
|
||||||
string coverUrl = $"https://uploads.mangadex.org/covers/{id}/{coverFileName}";
|
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);
|
null, 0f, year, originalLanguage);
|
||||||
return (manga, new MangaConnectorId<Manga>(manga, this, id, websiteUrl));
|
MangaConnectorId<Manga> mcId = new (manga, this, id, websiteUrl);
|
||||||
|
manga.MangaConnectorIds.Add(mcId);
|
||||||
|
return (manga, mcId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Chapter chapter, MangaConnectorId<Chapter> id) ParseChapterFromJToken(MangaConnectorId<Manga> mcIdManga, JToken jToken)
|
private (Chapter chapter, MangaConnectorId<Chapter> id) ParseChapterFromJToken(MangaConnectorId<Manga> mcIdManga, JToken jToken)
|
||||||
@@ -334,6 +336,8 @@ public class MangaDex : MangaConnector
|
|||||||
|
|
||||||
string websiteUrl = $"https://mangadex.org/chapter/{id}";
|
string websiteUrl = $"https://mangadex.org/chapter/{id}";
|
||||||
Chapter chapter = new (mcIdManga.Obj, chapterStr, volumeNumber, title);
|
Chapter chapter = new (mcIdManga.Obj, chapterStr, volumeNumber, title);
|
||||||
return (chapter, new MangaConnectorId<Chapter>(chapter, this, id, websiteUrl));
|
MangaConnectorId<Chapter> mcId = new(chapter, this, id, websiteUrl);
|
||||||
|
chapter.MangaConnectorIds.Add(mcId);
|
||||||
|
return (chapter, mcId);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -39,6 +39,7 @@ public class Chapter : Identifiable, IComparable<Chapter>
|
|||||||
this.Title = title;
|
this.Title = title;
|
||||||
this.FileName = GetArchiveFilePath();
|
this.FileName = GetArchiveFilePath();
|
||||||
this.Downloaded = false;
|
this.Downloaded = false;
|
||||||
|
this.MangaConnectorIds = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -61,6 +61,7 @@ public class Manga : Identifiable
|
|||||||
this.Year = year;
|
this.Year = year;
|
||||||
this.OriginalLanguage = originalLanguage;
|
this.OriginalLanguage = originalLanguage;
|
||||||
this.Chapters = [];
|
this.Chapters = [];
|
||||||
|
this.MangaConnectorIds = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -8,7 +8,7 @@ namespace API.Schema.MangaContext;
|
|||||||
[PrimaryKey("Key")]
|
[PrimaryKey("Key")]
|
||||||
public class MangaConnectorId<T> : Identifiable where T : Identifiable
|
public class MangaConnectorId<T> : 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!;
|
[JsonIgnore] public T Obj = null!;
|
||||||
|
|
||||||
[StringLength(32)] [Required] public string MangaConnectorName { get; private set; }
|
[StringLength(32)] [Required] public string MangaConnectorName { get; private set; }
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using API.MangaConnectors;
|
using API.MangaConnectors;
|
||||||
using API.Schema.MangaContext.MetadataFetchers;
|
using API.Schema.MangaContext.MetadataFetchers;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
|
|
||||||
namespace API.Schema.MangaContext;
|
namespace API.Schema.MangaContext;
|
||||||
|
|
||||||
@@ -102,4 +103,23 @@ public class MangaContext(DbContextOptions<MangaContext> options) : TrangaBaseCo
|
|||||||
.WithMany()
|
.WithMany()
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.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<Manga, ICollection<MangaConnectorId<Manga>>> 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);
|
||||||
}
|
}
|
@@ -9,7 +9,7 @@ using API.Workers;
|
|||||||
using API.Workers.MaintenanceWorkers;
|
using API.Workers.MaintenanceWorkers;
|
||||||
using log4net;
|
using log4net;
|
||||||
using log4net.Config;
|
using log4net.Config;
|
||||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace API;
|
namespace API;
|
||||||
|
|
||||||
@@ -162,30 +162,41 @@ public static class Tranga
|
|||||||
|
|
||||||
internal static bool AddMangaToContext(Manga addManga, MangaConnectorId<Manga> addMcId, MangaContext context, [NotNullWhen(true)]out Manga? manga)
|
internal static bool AddMangaToContext(Manga addManga, MangaConnectorId<Manga> addMcId, MangaContext context, [NotNullWhen(true)]out Manga? manga)
|
||||||
{
|
{
|
||||||
manga = context.Mangas.Find(addManga.Key) ?? addManga;
|
context.ChangeTracker.Clear();
|
||||||
MangaConnectorId<Manga> mcId = context.MangaConnectorToManga.Find(addMcId.Key) ?? addMcId;
|
manga = context.FindMangaLike(addManga);
|
||||||
mcId.Obj = manga;
|
if (manga is not null)
|
||||||
|
|
||||||
foreach (CollectionEntry collectionEntry in context.Entry(manga).Collections)
|
|
||||||
collectionEntry.Load();
|
|
||||||
context.Entry(manga).Navigation(nameof(Manga.Library)).Load();
|
|
||||||
|
|
||||||
IEnumerable<MangaTag> mergedTags = manga.MangaTags.Select(mt =>
|
|
||||||
{
|
{
|
||||||
MangaTag? inDb = context.Tags.Find(mt.Tag);
|
foreach (MangaConnectorId<Manga> mcId in addManga.MangaConnectorIds)
|
||||||
return inDb ?? mt;
|
{
|
||||||
});
|
mcId.Obj = manga;
|
||||||
manga.MangaTags = mergedTags.ToList();
|
mcId.ObjId = manga.Key;
|
||||||
|
}
|
||||||
IEnumerable<Author> mergedAuthors = manga.Authors.Select(ma =>
|
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
|
||||||
{
|
{
|
||||||
Author? inDb = context.Authors.Find(ma.Key);
|
manga = addManga;
|
||||||
return inDb ?? ma;
|
IEnumerable<MangaTag> mergedTags = manga.MangaTags.Select(mt =>
|
||||||
});
|
{
|
||||||
manga.Authors = mergedAuthors.ToList();
|
MangaTag? inDb = context.Tags.Find(mt.Tag);
|
||||||
|
return inDb ?? mt;
|
||||||
|
});
|
||||||
|
manga.MangaTags = mergedTags.ToList();
|
||||||
|
|
||||||
if(context.MangaConnectorToManga.Find(addMcId.Key) is null)
|
IEnumerable<Author> mergedAuthors = manga.Authors.Select(ma =>
|
||||||
context.MangaConnectorToManga.Add(mcId);
|
{
|
||||||
|
Author? inDb = context.Authors.Find(ma.Key);
|
||||||
|
return inDb ?? ma;
|
||||||
|
});
|
||||||
|
manga.Authors = mergedAuthors.ToList();
|
||||||
|
|
||||||
|
context.Mangas.Add(manga);
|
||||||
|
}
|
||||||
|
|
||||||
if (context.Sync() is { success: false })
|
if (context.Sync() is { success: false })
|
||||||
return false;
|
return false;
|
||||||
@@ -201,16 +212,19 @@ public static class Tranga
|
|||||||
|
|
||||||
internal static bool AddChapterToContext(Chapter addChapter, MangaConnectorId<Chapter> addChId, MangaContext context, [NotNullWhen(true)] out Chapter? chapter)
|
internal static bool AddChapterToContext(Chapter addChapter, MangaConnectorId<Chapter> addChId, MangaContext context, [NotNullWhen(true)] out Chapter? chapter)
|
||||||
{
|
{
|
||||||
chapter = context.Chapters.Find(addChapter.Key) ?? addChapter;
|
chapter = context.Chapters.Where(ch => ch.Key == addChapter.Key)
|
||||||
MangaConnectorId<Chapter> chId = context.MangaConnectorToChapter.Find(addChId.Key) ?? addChId;
|
.Include(ch => ch.ParentManga)
|
||||||
chId.Obj = chapter;
|
.Include(ch => ch.MangaConnectorIds)
|
||||||
|
.FirstOrDefault();
|
||||||
foreach (CollectionEntry collectionEntry in context.Entry(chapter).Collections)
|
if (chapter is not null)
|
||||||
collectionEntry.Load();
|
{
|
||||||
context.Entry(chapter).Navigation(nameof(Chapter.ParentManga)).Load();
|
chapter.MangaConnectorIds = chapter.MangaConnectorIds.UnionBy(addChapter.MangaConnectorIds, id => id.Key).ToList();
|
||||||
|
}
|
||||||
if(context.MangaConnectorToChapter.Find(chId.Key) is null)
|
else
|
||||||
context.MangaConnectorToChapter.Add(chId);
|
{
|
||||||
|
context.Chapters.Add(addChapter);
|
||||||
|
chapter = addChapter;
|
||||||
|
}
|
||||||
|
|
||||||
if (context.Sync() is { success: false })
|
if (context.Sync() is { success: false })
|
||||||
return false;
|
return false;
|
||||||
|
Reference in New Issue
Block a user