using MangaReader.Core.Data; using MangaReader.Core.Metadata; using Microsoft.EntityFrameworkCore; using System.Text.RegularExpressions; namespace MangaReader.Core.Pipeline; public partial class MangaPipeline(MangaContext context) : IMangaPipeline { public async Task RunAsync(SourceManga sourceManga) { Manga manga = await GetOrAddMangaAsync(sourceManga); foreach (SourceMangaTitle alternateTitle in sourceManga.AlternateTitles) { await AddTitleAsync(manga, alternateTitle); } foreach (string genre in sourceManga.Genres) { await LinkGenreAsync(manga, genre); } foreach (SourceMangaChapter chapter in sourceManga.Chapters) { await AddChapterAsync(manga, chapter); } context.SaveChanges(); } private async Task GetOrAddMangaAsync(SourceManga sourceManga) { Manga? manga = await context.Mangas.FirstOrDefaultAsync(manga => manga.Title == sourceManga.Title); if (manga != null) return manga; manga = new() { Title = sourceManga.Title, Slug = GenerateSlug(sourceManga.Title), }; context.Add(manga); return manga; } private static string GenerateSlug(string title) { title = title.ToLowerInvariant(); title = RemoveInvalidCharsRegex().Replace(title, ""); // remove invalid chars title = RemoveSpacesWithDashRegex().Replace(title, "-"); // replace spaces with dash return title.Trim('-'); } [GeneratedRegex(@"[^a-z0-9\s-]")] private static partial Regex RemoveInvalidCharsRegex(); [GeneratedRegex(@"\s+")] private static partial Regex RemoveSpacesWithDashRegex(); private async Task AddTitleAsync(Manga manga, SourceMangaTitle sourceMangaTitle) { MangaTitle? mangaTitle = await context.MangaTitles.FirstOrDefaultAsync(mt => mt.Manga == manga && mt.TitleEntry == sourceMangaTitle.Title); if (mangaTitle != null) return; mangaTitle = new() { Manga = manga, TitleEntry = sourceMangaTitle.Title, }; context.MangaTitles.Add(mangaTitle); } private async Task LinkGenreAsync(Manga manga, string genreName) { Genre genre = await GetOrAddGenreAsync(genreName); MangaGenre? mangaGenre = await context.MangaGenres.FirstOrDefaultAsync(x => x.Manga == manga && x.Genre == genre); if (mangaGenre != null) return; mangaGenre = new() { Manga = manga, Genre = genre }; context.MangaGenres.Add(mangaGenre); } private async Task GetOrAddGenreAsync(string genreName) { Genre? genre = await context.Genres.FirstOrDefaultAsync(x => x.Name == genreName); if (genre != null) return genre; genre = new() { Name = genreName, }; await context.Genres.AddAsync(genre); return genre; } private async Task AddChapterAsync(Manga manga, SourceMangaChapter sourceeMangaChapter) { MangaChapter mangaChapter = await context.MangaChapters.FirstOrDefaultAsync(x => x.ChapterNumber == sourceeMangaChapter.Number) ?? AddMangaChapter(manga, sourceeMangaChapter); if (mangaChapter.VolumeNumber is null && sourceeMangaChapter.Volume is not null) { mangaChapter.VolumeNumber = sourceeMangaChapter.Volume; } if (mangaChapter.Title is null && sourceeMangaChapter.Title is not null) { mangaChapter.Title = sourceeMangaChapter.Title; } } private MangaChapter AddMangaChapter(Manga manga, SourceMangaChapter sourceeMangaChapter) { MangaChapter mangaChapter = new() { Manga = manga, ChapterNumber = sourceeMangaChapter.Number }; context.MangaChapters.Add(mangaChapter); return mangaChapter; } }