Added Source Chapter and Source Page entities.

This commit is contained in:
2025-06-12 02:34:26 -04:00
parent 000a20bb0f
commit a82eab0ecb
18 changed files with 232 additions and 79 deletions

View File

@@ -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; } = [];
} }

View File

@@ -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);
} }
} }

View File

@@ -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; } = [];
} }

View File

@@ -0,0 +1,7 @@
namespace MangaReader.Core.Data;
public class ScanlationGroup
{
public int ScanlationGroupId { get; set; }
public required string Name { get; set; }
}

View 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; } = [];
}

View 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; }
}

View File

@@ -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>

View File

@@ -2,5 +2,6 @@
public interface IMangaPipeline public interface IMangaPipeline
{ {
Task RunAsync(MangaPipelineRequest request); Task RunMetadataAsync(MangaMetadataPipelineRequest request);
Task RunPagesAsync(MangaPagePipelineRequest request);
} }

View File

@@ -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; }

View 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; }
}

View File

@@ -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)
{ {
Manga = manga, SourceChapter sourceChapter = new()
ChapterNumber = sourceMangaChapter.Number {
MangaSource = mangaSource,
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;
}
} }
} }

View File

@@ -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; }

View File

@@ -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),

View File

@@ -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

View File

@@ -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>

View File

@@ -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();
} }
} }

View File

@@ -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"
} }
]); ]);

View File

@@ -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>