Added Source Chapter and Source Page entities.
This commit is contained in:
@@ -11,5 +11,5 @@ public class Manga
|
|||||||
public virtual ICollection<MangaSource> Sources { get; set; } = [];
|
public virtual ICollection<MangaSource> Sources { get; set; } = [];
|
||||||
public virtual ICollection<MangaContributor> Contributors { get; set; } = [];
|
public virtual ICollection<MangaContributor> Contributors { get; set; } = [];
|
||||||
public virtual ICollection<MangaGenre> Genres { get; set; } = [];
|
public virtual ICollection<MangaGenre> Genres { get; set; } = [];
|
||||||
public virtual ICollection<MangaChapter> Chapters { get; set; } = [];
|
//public virtual ICollection<MangaChapter> Chapters { get; set; } = [];
|
||||||
}
|
}
|
||||||
@@ -14,9 +14,11 @@ public class MangaContext(DbContextOptions options) : DbContext(options)
|
|||||||
public DbSet<MangaContributor> MangaContributors { get; set; }
|
public DbSet<MangaContributor> MangaContributors { get; set; }
|
||||||
public DbSet<Genre> Genres { get; set; }
|
public DbSet<Genre> Genres { get; set; }
|
||||||
public DbSet<MangaGenre> MangaGenres { get; set; }
|
public DbSet<MangaGenre> MangaGenres { get; set; }
|
||||||
public DbSet<MangaChapter> MangaChapters { get; set; }
|
//public DbSet<MangaChapter> MangaChapters { get; set; }
|
||||||
public DbSet<ChapterSource> ChapterSources { get; set; }
|
//public DbSet<ChapterSource> ChapterSources { get; set; }
|
||||||
public DbSet<ChapterPage> ChapterPages { get; set; }
|
//public DbSet<ChapterPage> ChapterPages { get; set; }
|
||||||
|
public DbSet<SourceChapter> SourceChapters { get; set; }
|
||||||
|
public DbSet<SourcePage> SourcePages { get; set; }
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
@@ -32,9 +34,11 @@ public class MangaContext(DbContextOptions options) : DbContext(options)
|
|||||||
ConfigureMangaContributor(modelBuilder);
|
ConfigureMangaContributor(modelBuilder);
|
||||||
ConfigureGenre(modelBuilder);
|
ConfigureGenre(modelBuilder);
|
||||||
ConfigureMangaGenre(modelBuilder);
|
ConfigureMangaGenre(modelBuilder);
|
||||||
ConfigureMangaChapter(modelBuilder);
|
//ConfigureMangaChapter(modelBuilder);
|
||||||
ConfigureChapterSource(modelBuilder);
|
//ConfigureChapterSource(modelBuilder);
|
||||||
ConfigureChapterPage(modelBuilder);
|
//ConfigureChapterPage(modelBuilder);
|
||||||
|
ConfigureSourceChapter(modelBuilder);
|
||||||
|
ConfigureSourcePage(modelBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConfigureManga(ModelBuilder modelBuilder)
|
private static void ConfigureManga(ModelBuilder modelBuilder)
|
||||||
@@ -152,7 +156,11 @@ public class MangaContext(DbContextOptions options) : DbContext(options)
|
|||||||
{
|
{
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.Entity<MangaSource>()
|
.Entity<MangaSource>()
|
||||||
.HasKey(mangaSource => new { mangaSource.MangaId, mangaSource.SourceId });
|
.HasKey(mangaSource => mangaSource.MangaSourceId);
|
||||||
|
|
||||||
|
//modelBuilder
|
||||||
|
// .Entity<MangaSource>()
|
||||||
|
// .HasKey(mangaSource => new { mangaSource.MangaId, mangaSource.SourceId });
|
||||||
|
|
||||||
modelBuilder.Entity<MangaSource>()
|
modelBuilder.Entity<MangaSource>()
|
||||||
.HasIndex(x => x.Url)
|
.HasIndex(x => x.Url)
|
||||||
@@ -218,50 +226,88 @@ public class MangaContext(DbContextOptions options) : DbContext(options)
|
|||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConfigureMangaChapter(ModelBuilder modelBuilder)
|
//private static void ConfigureMangaChapter(ModelBuilder modelBuilder)
|
||||||
|
//{
|
||||||
|
// modelBuilder
|
||||||
|
// .Entity<MangaChapter>()
|
||||||
|
// .HasKey(x => x.MangaChapterId);
|
||||||
|
|
||||||
|
// modelBuilder
|
||||||
|
// .Entity<MangaChapter>()
|
||||||
|
// .HasOne(x => x.Manga)
|
||||||
|
// .WithMany(x => x.Chapters)
|
||||||
|
// .HasForeignKey(x => x.MangaId)
|
||||||
|
// .OnDelete(DeleteBehavior.Cascade);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//private static void ConfigureChapterSource(ModelBuilder modelBuilder)
|
||||||
|
//{
|
||||||
|
// modelBuilder
|
||||||
|
// .Entity<ChapterSource>()
|
||||||
|
// .HasKey(chapterSource => new { chapterSource.MangaChapterId, chapterSource.SourceId });
|
||||||
|
|
||||||
|
// modelBuilder
|
||||||
|
// .Entity<ChapterSource>()
|
||||||
|
// .HasOne(x => x.Chapter)
|
||||||
|
// .WithMany(x => x.Sources)
|
||||||
|
// .HasForeignKey(x => x.MangaChapterId)
|
||||||
|
// .OnDelete(DeleteBehavior.Cascade);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//private static void ConfigureChapterPage(ModelBuilder modelBuilder)
|
||||||
|
//{
|
||||||
|
// modelBuilder
|
||||||
|
// .Entity<ChapterPage>()
|
||||||
|
// .HasKey(chapterPage => chapterPage.ChapterPageId);
|
||||||
|
|
||||||
|
// modelBuilder
|
||||||
|
// .Entity<ChapterPage>()
|
||||||
|
// .HasIndex(chapterPage => new { chapterPage.MangaChapterId, chapterPage.PageNumber })
|
||||||
|
// .IsUnique(true);
|
||||||
|
|
||||||
|
// modelBuilder
|
||||||
|
// .Entity<ChapterPage>()
|
||||||
|
// .HasOne(x => x.MangaChapter)
|
||||||
|
// .WithMany(x => x.Pages)
|
||||||
|
// .HasForeignKey(x => x.MangaChapterId)
|
||||||
|
// .OnDelete(DeleteBehavior.Cascade);
|
||||||
|
//}
|
||||||
|
|
||||||
|
private static void ConfigureSourceChapter(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.Entity<MangaChapter>()
|
.Entity<SourceChapter>()
|
||||||
.HasKey(x => x.MangaChapterId);
|
.HasKey(sourceChapter => sourceChapter.SourceChapterId);
|
||||||
|
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.Entity<MangaChapter>()
|
.Entity<SourceChapter>()
|
||||||
.HasOne(x => x.Manga)
|
.HasIndex(sourceChapter => new { sourceChapter.MangaSourceId, sourceChapter.ChapterNumber, sourceChapter.Url })
|
||||||
.WithMany(x => x.Chapters)
|
|
||||||
.HasForeignKey(x => x.MangaId)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureChapterSource(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder
|
|
||||||
.Entity<ChapterSource>()
|
|
||||||
.HasKey(chapterSource => new { chapterSource.MangaChapterId, chapterSource.SourceId });
|
|
||||||
|
|
||||||
modelBuilder
|
|
||||||
.Entity<ChapterSource>()
|
|
||||||
.HasOne(x => x.Chapter)
|
|
||||||
.WithMany(x => x.Sources)
|
|
||||||
.HasForeignKey(x => x.MangaChapterId)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureChapterPage(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder
|
|
||||||
.Entity<ChapterPage>()
|
|
||||||
.HasKey(chapterPage => chapterPage.ChapterPageId);
|
|
||||||
|
|
||||||
modelBuilder
|
|
||||||
.Entity<ChapterPage>()
|
|
||||||
.HasIndex(chapterPage => new { chapterPage.MangaChapterId, chapterPage.PageNumber })
|
|
||||||
.IsUnique(true);
|
.IsUnique(true);
|
||||||
|
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.Entity<ChapterPage>()
|
.Entity<SourceChapter>()
|
||||||
.HasOne(x => x.MangaChapter)
|
.HasOne(x => x.MangaSource)
|
||||||
|
.WithMany(x => x.Chapters)
|
||||||
|
.HasForeignKey(x => x.MangaSourceId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConfigureSourcePage(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.Entity<SourcePage>()
|
||||||
|
.HasKey(sourcePage => sourcePage.SourcePageId);
|
||||||
|
|
||||||
|
modelBuilder
|
||||||
|
.Entity<SourcePage>()
|
||||||
|
.HasIndex(sourcePage => new { sourcePage.SourceChapterId, sourcePage.PageNumber })
|
||||||
|
.IsUnique(true);
|
||||||
|
|
||||||
|
modelBuilder
|
||||||
|
.Entity<SourcePage>()
|
||||||
|
.HasOne(x => x.Chapter)
|
||||||
.WithMany(x => x.Pages)
|
.WithMany(x => x.Pages)
|
||||||
.HasForeignKey(x => x.MangaChapterId)
|
.HasForeignKey(x => x.SourceChapterId)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
public class MangaSource
|
public class MangaSource
|
||||||
{
|
{
|
||||||
|
public int MangaSourceId { get; set; }
|
||||||
|
|
||||||
public int MangaId { get; set; }
|
public int MangaId { get; set; }
|
||||||
public required Manga Manga { get; set; }
|
public required Manga Manga { get; set; }
|
||||||
|
|
||||||
@@ -9,4 +11,6 @@ public class MangaSource
|
|||||||
public required Source Source { get; set; }
|
public required Source Source { get; set; }
|
||||||
|
|
||||||
public required string Url { get; set; }
|
public required string Url { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<SourceChapter> Chapters { get; set; } = [];
|
||||||
}
|
}
|
||||||
7
MangaReader.Core/Data/ScanlationGroup.cs
Normal file
7
MangaReader.Core/Data/ScanlationGroup.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace MangaReader.Core.Data;
|
||||||
|
|
||||||
|
public class ScanlationGroup
|
||||||
|
{
|
||||||
|
public int ScanlationGroupId { get; set; }
|
||||||
|
public required string Name { get; set; }
|
||||||
|
}
|
||||||
20
MangaReader.Core/Data/SourceChapter.cs
Normal file
20
MangaReader.Core/Data/SourceChapter.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
namespace MangaReader.Core.Data;
|
||||||
|
|
||||||
|
public class SourceChapter
|
||||||
|
{
|
||||||
|
public int SourceChapterId { get; set; }
|
||||||
|
|
||||||
|
public int MangaSourceId { get; set; }
|
||||||
|
public required MangaSource MangaSource { get; set; }
|
||||||
|
|
||||||
|
public int? ScanlationGroupId { get; set; }
|
||||||
|
public ScanlationGroup? ScanlationGroup { get; set; }
|
||||||
|
|
||||||
|
public required float ChapterNumber { get; set; }
|
||||||
|
public int? VolumeNumber { get; set; }
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
public required string Url { get; set; }
|
||||||
|
|
||||||
|
public ICollection<SourcePage> Pages { get; set; } = [];
|
||||||
|
}
|
||||||
12
MangaReader.Core/Data/SourcePage.cs
Normal file
12
MangaReader.Core/Data/SourcePage.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace MangaReader.Core.Data;
|
||||||
|
|
||||||
|
public class SourcePage
|
||||||
|
{
|
||||||
|
public int SourcePageId { get; set; }
|
||||||
|
|
||||||
|
public int SourceChapterId { get; set; }
|
||||||
|
public required SourceChapter Chapter { get; set; }
|
||||||
|
|
||||||
|
public int PageNumber { get; set; }
|
||||||
|
public required string Url { get; set; }
|
||||||
|
}
|
||||||
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.1" />
|
<PackageReference Include="HtmlAgilityPack" Version="1.12.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.6" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
|
|
||||||
public interface IMangaPipeline
|
public interface IMangaPipeline
|
||||||
{
|
{
|
||||||
Task RunAsync(MangaPipelineRequest request);
|
Task RunMetadataAsync(MangaMetadataPipelineRequest request);
|
||||||
|
Task RunPagesAsync(MangaPagePipelineRequest request);
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
namespace MangaReader.Core.Pipeline;
|
namespace MangaReader.Core.Pipeline;
|
||||||
|
|
||||||
public class MangaPipelineRequest
|
public class MangaMetadataPipelineRequest
|
||||||
{
|
{
|
||||||
|
public int? MangaId { get; init; }
|
||||||
public required string SourceName { get; init; }
|
public required string SourceName { get; init; }
|
||||||
public required string SourceUrl { get; init; }
|
public required string SourceUrl { get; init; }
|
||||||
public required SourceManga SourceManga { get; init; }
|
public required SourceManga SourceManga { get; init; }
|
||||||
7
MangaReader.Core/Pipeline/MangaPagePipelineRequest.cs
Normal file
7
MangaReader.Core/Pipeline/MangaPagePipelineRequest.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace MangaReader.Core.Pipeline;
|
||||||
|
|
||||||
|
public class MangaPagePipelineRequest
|
||||||
|
{
|
||||||
|
public required int SourceChapterId { get; init; }
|
||||||
|
public required IReadOnlyList<string> PageImageUrls { get; init; }
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
|
|||||||
Secondary
|
Secondary
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RunAsync(MangaPipelineRequest request)
|
public async Task RunMetadataAsync(MangaMetadataPipelineRequest request)
|
||||||
{
|
{
|
||||||
string sourceName = request.SourceName;
|
string sourceName = request.SourceName;
|
||||||
string sourceUrl = request.SourceUrl;
|
string sourceUrl = request.SourceUrl;
|
||||||
@@ -21,8 +21,8 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
|
|||||||
|
|
||||||
Source source = await GetOrAddSourceAsync(sourceName);
|
Source source = await GetOrAddSourceAsync(sourceName);
|
||||||
Manga manga = await GetOrAddMangaAsync(sourceManga);
|
Manga manga = await GetOrAddMangaAsync(sourceManga);
|
||||||
|
MangaSource mangaSource = await AddMangaSourceAsync(sourceUrl, manga, source);
|
||||||
|
|
||||||
await AddMangaSourceAsync(sourceUrl, manga, source);
|
|
||||||
await AddTitleAsync(manga, sourceManga.Title, TitleType.Primary);
|
await AddTitleAsync(manga, sourceManga.Title, TitleType.Primary);
|
||||||
await AddDescriptionAsync(manga, sourceManga.Description);
|
await AddDescriptionAsync(manga, sourceManga.Description);
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
|
|||||||
|
|
||||||
foreach (SourceMangaChapter chapter in sourceManga.Chapters)
|
foreach (SourceMangaChapter chapter in sourceManga.Chapters)
|
||||||
{
|
{
|
||||||
await AddChapterAsync(manga, chapter);
|
await AddChapterAsync(mangaSource, chapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
@@ -94,13 +94,13 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
|
|||||||
[GeneratedRegex(@"\s+")]
|
[GeneratedRegex(@"\s+")]
|
||||||
private static partial Regex RemoveSpacesWithDashRegex();
|
private static partial Regex RemoveSpacesWithDashRegex();
|
||||||
|
|
||||||
private async Task AddMangaSourceAsync(string sourceUrl, Manga manga, Source source)
|
private async Task<MangaSource> AddMangaSourceAsync(string sourceUrl, Manga manga, Source source)
|
||||||
{
|
{
|
||||||
MangaSource? mangaSource = await context.MangaSources.FirstOrDefaultAsync(ms =>
|
MangaSource? mangaSource = await context.MangaSources.FirstOrDefaultAsync(ms =>
|
||||||
ms.Manga == manga && ms.Source == source && ms.Url == sourceUrl);
|
ms.Manga == manga && ms.Source == source && ms.Url == sourceUrl);
|
||||||
|
|
||||||
if (mangaSource != null)
|
if (mangaSource != null)
|
||||||
return;
|
return mangaSource;
|
||||||
|
|
||||||
mangaSource = new()
|
mangaSource = new()
|
||||||
{
|
{
|
||||||
@@ -110,6 +110,8 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
|
|||||||
};
|
};
|
||||||
|
|
||||||
context.MangaSources.Add(mangaSource);
|
context.MangaSources.Add(mangaSource);
|
||||||
|
|
||||||
|
return mangaSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddTitleAsync(Manga manga, SourceMangaTitle sourceMangaTitle, TitleType titleType)
|
private async Task AddTitleAsync(Manga manga, SourceMangaTitle sourceMangaTitle, TitleType titleType)
|
||||||
@@ -187,32 +189,76 @@ public partial class MangaPipeline(MangaContext context) : IMangaPipeline
|
|||||||
return genre;
|
return genre;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddChapterAsync(Manga manga, SourceMangaChapter sourceMangaChapter)
|
private async Task AddChapterAsync(MangaSource mangaSource, SourceMangaChapter sourceMangaChapter)
|
||||||
{
|
{
|
||||||
MangaChapter mangaChapter = await context.MangaChapters.FirstOrDefaultAsync(x => x.ChapterNumber == sourceMangaChapter.Number)
|
SourceChapter sourceChapter = await GetSourceChapter(mangaSource, sourceMangaChapter)
|
||||||
?? AddMangaChapter(manga, sourceMangaChapter);
|
?? AddSourceChapter(mangaSource, sourceMangaChapter);
|
||||||
|
|
||||||
if (mangaChapter.VolumeNumber is null && sourceMangaChapter.Volume is not null)
|
if (sourceChapter.VolumeNumber is null && sourceMangaChapter.Volume is not null)
|
||||||
{
|
{
|
||||||
mangaChapter.VolumeNumber = sourceMangaChapter.Volume;
|
sourceChapter.VolumeNumber = sourceMangaChapter.Volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mangaChapter.Title is null && sourceMangaChapter.Title is not null)
|
if (sourceChapter.Title is null && sourceMangaChapter.Title is not null)
|
||||||
{
|
{
|
||||||
mangaChapter.Title = sourceMangaChapter.Title;
|
sourceChapter.Title = sourceMangaChapter.Title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MangaChapter AddMangaChapter(Manga manga, SourceMangaChapter sourceMangaChapter)
|
private async Task<SourceChapter?> GetSourceChapter(MangaSource mangaSource, SourceMangaChapter sourceMangaChapter)
|
||||||
{
|
{
|
||||||
MangaChapter mangaChapter = new()
|
return await context.SourceChapters.FirstOrDefaultAsync(x =>
|
||||||
|
x.MangaSource == mangaSource && x.ChapterNumber == sourceMangaChapter.Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SourceChapter AddSourceChapter(MangaSource mangaSource, SourceMangaChapter sourceMangaChapter)
|
||||||
|
{
|
||||||
|
SourceChapter sourceChapter = new()
|
||||||
{
|
{
|
||||||
Manga = manga,
|
MangaSource = mangaSource,
|
||||||
ChapterNumber = sourceMangaChapter.Number
|
ChapterNumber = sourceMangaChapter.Number,
|
||||||
|
Url = sourceMangaChapter.Url
|
||||||
};
|
};
|
||||||
|
|
||||||
context.MangaChapters.Add(mangaChapter);
|
context.SourceChapters.Add(sourceChapter);
|
||||||
|
|
||||||
return mangaChapter;
|
return sourceChapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunPagesAsync(MangaPagePipelineRequest request)
|
||||||
|
{
|
||||||
|
SourceChapter? sourceChapter = await context.SourceChapters.FirstOrDefaultAsync(x => x.SourceChapterId == request.SourceChapterId);
|
||||||
|
|
||||||
|
if (sourceChapter == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int currentPageNumber = 1;
|
||||||
|
|
||||||
|
foreach (string pageImageUrl in request.PageImageUrls)
|
||||||
|
{
|
||||||
|
await AddOrUpdateSourcePageAsync(sourceChapter, currentPageNumber++, pageImageUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddOrUpdateSourcePageAsync(SourceChapter sourceChapter, int pageNumber, string pageImageUrl)
|
||||||
|
{
|
||||||
|
SourcePage? sourcePage = await context.SourcePages.FirstOrDefaultAsync(x =>
|
||||||
|
x.Chapter == sourceChapter && x.PageNumber == pageNumber);
|
||||||
|
|
||||||
|
if (sourcePage == null)
|
||||||
|
{
|
||||||
|
sourcePage = new()
|
||||||
|
{
|
||||||
|
Chapter = sourceChapter,
|
||||||
|
PageNumber = pageNumber,
|
||||||
|
Url = pageImageUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
context.SourcePages.Add(sourcePage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sourcePage.Url = pageImageUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
public record MangaSearchResult
|
public record MangaSearchResult
|
||||||
{
|
{
|
||||||
|
public required string Source { get; init; }
|
||||||
public required string Url { get; init; }
|
public required string Url { get; init; }
|
||||||
public required string Title { get; init; }
|
public required string Title { get; init; }
|
||||||
public string? Thumbnail { get; init; }
|
public string? Thumbnail { get; init; }
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public partial class MangaDexSearchProvider(IMangaDexClient mangaDexClient) : IM
|
|||||||
return [.. mangaSearchResults];
|
return [.. mangaSearchResults];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MangaSearchResult? GetMangaSearchResult(MangaEntity mangaEntity, CoverArtEntity[] coverArtEntites)
|
private MangaSearchResult? GetMangaSearchResult(MangaEntity mangaEntity, CoverArtEntity[] coverArtEntites)
|
||||||
{
|
{
|
||||||
MangaAttributes? mangaAttributes = mangaEntity.Attributes;
|
MangaAttributes? mangaAttributes = mangaEntity.Attributes;
|
||||||
|
|
||||||
@@ -65,6 +65,7 @@ public partial class MangaDexSearchProvider(IMangaDexClient mangaDexClient) : IM
|
|||||||
|
|
||||||
MangaSearchResult mangaSearchResult = new()
|
MangaSearchResult mangaSearchResult = new()
|
||||||
{
|
{
|
||||||
|
Source = SourceId,
|
||||||
Title = title,
|
Title = title,
|
||||||
Description = GetDescription(mangaAttributes),
|
Description = GetDescription(mangaAttributes),
|
||||||
Genres = GetGenres(mangaAttributes),
|
Genres = GetGenres(mangaAttributes),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public partial class NatoMangaSearchProvider(INatoMangaClient natoMangaClient) :
|
|||||||
{
|
{
|
||||||
MangaSearchResult mangaSearchResult = new()
|
MangaSearchResult mangaSearchResult = new()
|
||||||
{
|
{
|
||||||
|
Source = SourceId,
|
||||||
Title = searchResult.Name,
|
Title = searchResult.Name,
|
||||||
Thumbnail = searchResult.Thumb,
|
Thumbnail = searchResult.Thumb,
|
||||||
Url = searchResult.Url
|
Url = searchResult.Url
|
||||||
|
|||||||
@@ -42,12 +42,12 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.6" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||||
<PackageReference Include="Shouldly" Version="4.3.0" />
|
<PackageReference Include="Shouldly" Version="4.3.0" />
|
||||||
<PackageReference Include="xunit" Version="2.9.3" />
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.0">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ public class MangaPipelineTests(TestDbContextFactory factory) : IClassFixture<Te
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
MangaPipelineRequest request = new()
|
MangaMetadataPipelineRequest request = new()
|
||||||
{
|
{
|
||||||
SourceName = "MySource",
|
SourceName = "MySource",
|
||||||
SourceUrl = "https://wwww.mymangasource.org/my-manga",
|
SourceUrl = "https://wwww.mymangasource.org/my-manga",
|
||||||
SourceManga = sourceManga
|
SourceManga = sourceManga
|
||||||
};
|
};
|
||||||
|
|
||||||
await pipeline.RunAsync(request);
|
await pipeline.RunMetadataAsync(request);
|
||||||
|
|
||||||
context.Mangas.ShouldHaveSingleItem();
|
context.Mangas.ShouldHaveSingleItem();
|
||||||
context.MangaTitles.Count().ShouldBe(2);
|
context.MangaTitles.Count().ShouldBe(2);
|
||||||
@@ -58,6 +58,6 @@ public class MangaPipelineTests(TestDbContextFactory factory) : IClassFixture<Te
|
|||||||
context.MangaTitles.Where(mt => mt.IsPrimary).First().Name.ShouldBe("Fullmetal Alchemist");
|
context.MangaTitles.Where(mt => mt.IsPrimary).First().Name.ShouldBe("Fullmetal Alchemist");
|
||||||
context.MangaTitles.Where(mt => mt.IsPrimary).First().Language.ShouldBe(Language.English);
|
context.MangaTitles.Where(mt => mt.IsPrimary).First().Language.ShouldBe(Language.English);
|
||||||
context.Genres.Count().ShouldBe(2);
|
context.Genres.Count().ShouldBe(2);
|
||||||
context.MangaChapters.ShouldHaveSingleItem();
|
context.SourceChapters.ShouldHaveSingleItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,14 +16,16 @@ public class MangaSearchCoordinatorTests
|
|||||||
[
|
[
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Title = "Test Manga 1",
|
Source = "Manga Source 1",
|
||||||
Url = "https://mangasource1.com/manga/1",
|
Url = "https://mangasource1.com/manga/1",
|
||||||
|
Title = "Test Manga 1",
|
||||||
Thumbnail = "https://mangasource1.com/manga/cover/1.png"
|
Thumbnail = "https://mangasource1.com/manga/cover/1.png"
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
Source = "Manga Source 1",
|
||||||
|
Url = "https://mangasource1.com/manga/2",
|
||||||
Title = "Test Manga 2",
|
Title = "Test Manga 2",
|
||||||
Url = "https://mangasource2.com/manga/2",
|
|
||||||
Thumbnail = "https://mangasource2.com/manga/cover/2.png"
|
Thumbnail = "https://mangasource2.com/manga/cover/2.png"
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
@@ -35,8 +37,9 @@ public class MangaSearchCoordinatorTests
|
|||||||
[
|
[
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
Source = "Manga Source 2",
|
||||||
|
Url = "https://mangasource2.com/manga/3",
|
||||||
Title = "Test Manga 3",
|
Title = "Test Manga 3",
|
||||||
Url = "https://mangasource3.com/manga/3",
|
|
||||||
Thumbnail = "https://mangasource3.com/manga/cover/3.png"
|
Thumbnail = "https://mangasource3.com/manga/cover/3.png"
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -57,14 +60,16 @@ public class MangaSearchCoordinatorTests
|
|||||||
[
|
[
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Title = "Test Manga 1",
|
Source = "Manga Source 1",
|
||||||
Url = "https://mangasource1.com/manga/1",
|
Url = "https://mangasource1.com/manga/1",
|
||||||
|
Title = "Test Manga 1",
|
||||||
Thumbnail = "https://mangasource1.com/manga/cover/1.png"
|
Thumbnail = "https://mangasource1.com/manga/cover/1.png"
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
Source = "Manga Source 1",
|
||||||
|
Url = "https://mangasource1.com/manga/2",
|
||||||
Title = "Test Manga 2",
|
Title = "Test Manga 2",
|
||||||
Url = "https://mangasource2.com/manga/2",
|
|
||||||
Thumbnail = "https://mangasource2.com/manga/cover/2.png"
|
Thumbnail = "https://mangasource2.com/manga/cover/2.png"
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
@@ -73,8 +78,9 @@ public class MangaSearchCoordinatorTests
|
|||||||
[
|
[
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
Source = "Manga Source 2",
|
||||||
|
Url = "https://mangasource2.com/manga/3",
|
||||||
Title = "Test Manga 3",
|
Title = "Test Manga 3",
|
||||||
Url = "https://mangasource3.com/manga/3",
|
|
||||||
Thumbnail = "https://mangasource3.com/manga/cover/3.png"
|
Thumbnail = "https://mangasource3.com/manga/cover/3.png"
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" />
|
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" />
|
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.250402" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250513003" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.9" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.9" />
|
||||||
<PackageReference Include="SkiaSharp" Version="3.119.0" />
|
<PackageReference Include="SkiaSharp" Version="3.119.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user