Added more UI logic. Added a manga pipeline test.

This commit is contained in:
2025-06-04 02:21:30 -04:00
parent 7dbcdc6169
commit 70513559cb
21 changed files with 264 additions and 73 deletions

View File

@@ -0,0 +1,8 @@
namespace MangaReader.Core.Common;
public enum Language
{
Japanese,
Romanji,
English
}

View File

@@ -81,12 +81,12 @@ public class MangaContext(DbContextOptions options) : DbContext(options)
.HasKey(mangaTitle => mangaTitle.MangaTitleId);
modelBuilder.Entity<MangaTitle>()
.HasIndex(mangaTitle => new { mangaTitle.MangaId, mangaTitle.TitleEntry })
.HasIndex(mangaTitle => new { mangaTitle.MangaId, mangaTitle.Name })
.IsUnique();
modelBuilder
.Entity<MangaTitle>()
.HasIndex(mangaTitle => mangaTitle.TitleEntry);
.HasIndex(mangaTitle => mangaTitle.Name);
modelBuilder
.Entity<MangaTitle>()

View File

@@ -0,0 +1,14 @@
using MangaReader.Core.Common;
namespace MangaReader.Core.Data;
public class MangaDescription
{
public int MangaTitleId { get; set; }
public int MangaId { get; set; }
public required Manga Manga { get; set; }
public required string Name { get; set; }
public required Language Language { get; set; }
}

View File

@@ -7,6 +7,6 @@ public class MangaTitle
public int MangaId { get; set; }
public required Manga Manga { get; set; }
public required string TitleEntry { get; set; }
public required string Name { get; set; }
public TitleType TitleType { get; set; }
}

View File

@@ -1,8 +1,6 @@
using MangaReader.Core.Metadata;
namespace MangaReader.Core.Pipeline;
namespace MangaReader.Core.Pipeline;
public interface IMangaPipeline
{
Task RunAsync(SourceManga mangaDto);
Task RunAsync(MangaPipelineRequest request);
}

View File

@@ -7,8 +7,12 @@ namespace MangaReader.Core.Pipeline;
public partial class MangaPipeline(MangaContext context) : IMangaPipeline
{
public async Task RunAsync(SourceManga sourceManga)
public async Task RunAsync(MangaPipelineRequest request)
{
string sourceName = request.SourceName;
SourceManga sourceManga = request.SourceManga;
Source source = await GetOrAddSourceAsync(sourceName);
Manga manga = await GetOrAddMangaAsync(sourceManga);
foreach (SourceMangaTitle alternateTitle in sourceManga.AlternateTitles)
@@ -29,6 +33,23 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
context.SaveChanges();
}
private async Task<Source> GetOrAddSourceAsync(string sourceName)
{
Source? source = await context.Sources.FirstOrDefaultAsync(s => s.Name == sourceName);
if (source != null)
return source;
source = new()
{
Name = sourceName
};
context.Sources.Add(source);
return source;
}
private async Task<Manga> GetOrAddMangaAsync(SourceManga sourceManga)
{
Manga? manga = await context.Mangas.FirstOrDefaultAsync(manga => manga.Title == sourceManga.Title);
@@ -65,7 +86,7 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
private async Task AddTitleAsync(Manga manga, SourceMangaTitle sourceMangaTitle)
{
MangaTitle? mangaTitle = await context.MangaTitles.FirstOrDefaultAsync(mt =>
mt.Manga == manga && mt.TitleEntry == sourceMangaTitle.Title);
mt.Manga == manga && mt.Name == sourceMangaTitle.Title);
if (mangaTitle != null)
return;
@@ -73,7 +94,7 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
mangaTitle = new()
{
Manga = manga,
TitleEntry = sourceMangaTitle.Title,
Name = sourceMangaTitle.Title,
};
context.MangaTitles.Add(mangaTitle);

View File

@@ -0,0 +1,9 @@
using MangaReader.Core.Metadata;
namespace MangaReader.Core.Pipeline;
public class MangaPipelineRequest
{
public required string SourceName { get; init; }
public required SourceManga SourceManga { get; init; }
}

View File

@@ -7,4 +7,5 @@ public record MangaSearchResult
public string? Thumbnail { get; init; }
public string? Author { get; init; }
public string? Description { get; init; }
public string[] Genres { get; init; } = [];
}

View File

@@ -67,6 +67,7 @@ public partial class MangaDexSearchProvider(IMangaDexClient mangaDexClient) : IM
{
Title = title,
Description = GetDescription(mangaAttributes),
Genres = GetGenres(mangaAttributes),
Url = $"https://mangadex.org/title/{mangaEntity.Id}/{slug}",
Thumbnail = GetThumbnail(mangaEntity, coverArtEntites)
};
@@ -95,9 +96,33 @@ public partial class MangaDexSearchProvider(IMangaDexClient mangaDexClient) : IM
if (attributes.Description.TryGetValue("en", out string? description))
return description;
if (attributes.Description.Count > 0)
return attributes.Description.ElementAt(0).Value;
return string.Empty;
}
private static string[] GetGenres(MangaAttributes attributes)
{
if (attributes.Tags == null || attributes.Tags.Count == 0)
return [];
List<string> tags = [];
foreach (TagEntity tagEntity in attributes.Tags)
{
if (tagEntity.Attributes == null)
continue;
if (tagEntity.Attributes.Name == null || tagEntity.Attributes.Name.Count == 0)
continue;
tags.Add(tagEntity.Attributes.Name.FirstOrDefault().Value);
}
return [.. tags];
}
public static string GenerateSlug(string title)
{
// title.ToLowerInvariant().Normalize(NormalizationForm.FormD);