Skip to content

Commit

Permalink
Foundational Rework (Round 2) (#2767)
Browse files Browse the repository at this point in the history
  • Loading branch information
majora2007 authored Mar 7, 2024
1 parent 304fd8b commit fc87dba
Show file tree
Hide file tree
Showing 29 changed files with 249 additions and 84 deletions.
26 changes: 26 additions & 0 deletions API.Tests/Extensions/ChapterListExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,32 @@ public void GetChapterByRange_On_Duplicate_Files_Test_Should_Not_Error()
Assert.Equal(chapterList[0], actualChapter);
}

[Fact]
public void GetChapterByRange_On_FilenameChange_ShouldGetChapter()
{
var info = new ParserInfo()
{
Chapters = "1",
Edition = "",
Format = MangaFormat.Archive,
FullFilePath = "/manga/detective comics #001.cbz",
Filename = "detective comics #001.cbz",
IsSpecial = false,
Series = "detective comics",
Title = "detective comics",
Volumes = API.Services.Tasks.Scanner.Parser.Parser.LooseLeafVolume
};

var chapterList = new List<Chapter>()
{
CreateChapter("1", "1", CreateFile("/manga/detective comics #001.cbz", MangaFormat.Archive), false),
};

var actualChapter = chapterList.GetChapterByRange(info);

Assert.Equal(chapterList[0], actualChapter);
}

#region GetFirstChapterWithFiles

[Fact]
Expand Down
29 changes: 26 additions & 3 deletions API.Tests/Extensions/ParserInfoListExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions.TestingHelpers;
using System.Linq;
using API.Entities.Enums;
Expand Down Expand Up @@ -33,16 +34,16 @@ public void DistinctVolumesTest(string[] volumeNumbers, string[] expectedNumbers

[Theory]
[InlineData(new[] {@"Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, true)]
[InlineData(new[] {@"Cynthia The Mission - c000-006 (v06-07) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, true)]
[InlineData(new[] {@"Cynthia The Mission - c000-006 (v06-07) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, false)]
[InlineData(new[] {@"Cynthia The Mission v20 c12-20 [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, false)]
public void HasInfoTest(string[] inputInfos, string[] inputChapters, bool expectedHasInfo)
{
var infos = new List<ParserInfo>();
foreach (var filename in inputInfos)
{
infos.Add(_defaultParser.Parse(
filename,
string.Empty));
Path.Join("E:/Manga/Cynthia the Mission/", filename),
"E:/Manga/"));
}

var files = inputChapters.Select(s => new MangaFileBuilder(s, MangaFormat.Archive, 199).Build()).ToList();
Expand All @@ -52,4 +53,26 @@ public void HasInfoTest(string[] inputInfos, string[] inputChapters, bool expect

Assert.Equal(expectedHasInfo, infos.HasInfo(chapter));
}

[Fact]
public void HasInfoTest_SuccessWhenSpecial()
{
var infos = new[]
{
_defaultParser.Parse(
"E:/Manga/Cynthia the Mission/Cynthia The Mission The Special SP01 [Desudesu&Brolen].zip",
"E:/Manga/")
};

var files = new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission The Special SP01 [Desudesu&Brolen].zip"}
.Select(s => new MangaFileBuilder(s, MangaFormat.Archive, 199).Build())
.ToList();
var chapter = new ChapterBuilder("Cynthia The Mission The Special SP01 [Desudesu&Brolen].zip")
.WithRange("Cynthia The Mission The Special SP01 [Desudesu&Brolen]")
.WithFiles(files)
.WithIsSpecial(true)
.Build();

Assert.True(infos.HasInfo(chapter));
}
}
2 changes: 1 addition & 1 deletion API.Tests/Services/SeriesServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ public async Task SeriesDetail_WhenBookLibrary_ShouldReturnVolumesAndSpecial()
Assert.Equal("2 - Ano Orokamono ni mo Kyakkou wo! - Volume 2", detail.Volumes.ElementAt(0).Name);

Assert.NotEmpty(detail.Specials);
Assert.Equal("Ano Orokamono ni mo Kyakkou wo! - Volume 1.epub", detail.Specials.ElementAt(0).Range);
Assert.Equal("Ano Orokamono ni mo Kyakkou wo! - Volume 1", detail.Specials.ElementAt(0).Range);

// A book library where all books are Volumes, will show no "chapters" on the UI because it doesn't make sense
Assert.Empty(detail.Chapters);
Expand Down
9 changes: 8 additions & 1 deletion API/DTOs/ChapterDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@ public class ChapterDto : IHasReadTimeEstimate
/// <summary>
/// Range of chapters. Chapter 2-4 -> "2-4". Chapter 2 -> "2". If special, will be special name.
/// </summary>
/// <remarks>This can be something like 19.HU or Alpha as some comics are like this</remarks>
public string Range { get; init; } = default!;
/// <summary>
/// Smallest number of the Range.
/// </summary>
[Obsolete("Use MinNumber and MaxNumber instead")]
public string Number { get; init; } = default!;
/// <summary>
/// This may be 0 under the circumstance that the Issue is "Alpha" or other non-standard numbers.
/// </summary>
public float MinNumber { get; init; }
public float MaxNumber { get; init; }
public float SortOrder { get; init; }
/// <summary>
/// The sorting order of the Chapter. Inherits from MinNumber, but can be overridden.
/// </summary>
public float SortOrder { get; set; }
/// <summary>
/// Total number of pages in all MangaFiles
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion API/Data/ManualMigrations/MigrateChapterFields.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static async Task Migrate(DataContext dataContext, IUnitOfWork unitOfWork
"Running MigrateChapterFields migration - Updating all MangaFiles");
foreach (var mangaFile in dataContext.MangaFile)
{
mangaFile.FileName = Path.GetFileNameWithoutExtension(mangaFile.FilePath);
mangaFile.FileName = Parser.RemoveExtensionIfSupported(mangaFile.FilePath);
}

var looseLeafChapters = await dataContext.Chapter.Where(c => c.Number == "0").ToListAsync();
Expand Down
55 changes: 55 additions & 0 deletions API/Data/ManualMigrations/MigrateChapterRange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using API.Entities;
using API.Helpers.Builders;
using API.Services.Tasks.Scanner.Parser;
using Kavita.Common.EnvironmentInfo;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace API.Data.ManualMigrations;

/// <summary>
/// v0.8.0 changed the range to that it doesn't have filename by default
/// </summary>
public static class MigrateChapterRange
{
public static async Task Migrate(DataContext dataContext, IUnitOfWork unitOfWork, ILogger<Program> logger)
{
if (await dataContext.ManualMigrationHistory.AnyAsync(m => m.Name == "MigrateChapterRange"))
{
return;
}

logger.LogCritical(
"Running MigrateChapterRange migration - Please be patient, this may take some time. This is not an error");

var chapters = await dataContext.Chapter.ToListAsync();
foreach (var chapter in chapters)
{
if (Parser.MinNumberFromRange(chapter.Range) == 0.0f)
{
chapter.Range = chapter.GetNumberTitle();
}
}


// Save changes after processing all series
if (dataContext.ChangeTracker.HasChanges())
{
await dataContext.SaveChangesAsync();
}

dataContext.ManualMigrationHistory.Add(new ManualMigrationHistory()
{
Name = "MigrateChapterRange",
ProductVersion = BuildInfo.Version.ToString(),
RanAt = DateTime.UtcNow
});

await dataContext.SaveChangesAsync();
logger.LogCritical(
"Running MigrateChapterRange migration - Completed. This is not an error");
}
}
1 change: 1 addition & 0 deletions API/Data/Repositories/SeriesRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ public async Task<SearchResultGroupDto> SearchSeries(int userId, bool isAdmin, I
.Include(c => c.Files)
.Where(c => EF.Functions.Like(c.TitleName, $"%{searchQuery}%")
|| EF.Functions.Like(c.ISBN, $"%{searchQuery}%")
|| EF.Functions.Like(c.Range, $"%{searchQuery}%")
)
.Where(c => c.Files.All(f => fileIds.Contains(f.Id)))
.AsSplitQuery()
Expand Down
14 changes: 10 additions & 4 deletions API/Entities/Chapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,13 @@ public void UpdateFrom(ParserInfo info)
MinNumber = Parser.DefaultChapterNumber;
MaxNumber = Parser.DefaultChapterNumber;
}
// NOTE: This doesn't work well for all because Pdf usually should use into.Title or even filename
Title = (IsSpecial && info.Format == MangaFormat.Epub)
? info.Title
: Path.GetFileNameWithoutExtension(Range);
: Parser.RemoveExtensionIfSupported(Range);

var specialTreatment = info.IsSpecialInfo();
Range = specialTreatment ? info.Filename : info.Chapters;
}

/// <summary>
Expand All @@ -165,13 +168,16 @@ public string GetNumberTitle()
{
if (MinNumber.Is(Parser.DefaultChapterNumber) && IsSpecial)
{
return Title;
return Parser.RemoveExtensionIfSupported(Title);
}
else

if (MinNumber.Is(0) && !float.TryParse(Range, out _))
{
return $"{MinNumber}";
return $"{Range}";
}

return $"{MinNumber}";

}
return $"{MinNumber}-{MaxNumber}";
}
Expand Down
7 changes: 4 additions & 3 deletions API/Extensions/ChapterListExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ public static class ChapterListExtensions
/// <returns></returns>
public static Chapter? GetChapterByRange(this IEnumerable<Chapter> chapters, ParserInfo info)
{
var normalizedPath = Parser.NormalizePath(info.FullFilePath);
var specialTreatment = info.IsSpecialInfo();
return specialTreatment
? chapters.FirstOrDefault(c => c.Range == Path.GetFileNameWithoutExtension(info.Filename) || (c.Files.Select(f => f.FilePath).Contains(info.FullFilePath)))
: chapters.FirstOrDefault(c => c.Range == info.Chapters);
return specialTreatment
? chapters.FirstOrDefault(c => c.Range == Parser.RemoveExtensionIfSupported(info.Filename) || c.Files.Select(f => Parser.NormalizePath(f.FilePath)).Contains(normalizedPath))
: chapters.FirstOrDefault(c => c.Range == info.Chapters);
}

/// <summary>
Expand Down
7 changes: 5 additions & 2 deletions API/Extensions/ParserInfoListExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using API.Entities;
using API.Services.Tasks.Scanner.Parser;
Expand Down Expand Up @@ -27,7 +28,9 @@ public static IList<string> DistinctVolumes(this IList<ParserInfo> infos)
/// <returns></returns>
public static bool HasInfo(this IList<ParserInfo> infos, Chapter chapter)
{
return chapter.IsSpecial ? infos.Any(v => v.Filename == chapter.Range)
: infos.Any(v => v.Chapters == chapter.Range);
var chapterFiles = chapter.Files.Select(x => Parser.NormalizePath(x.FilePath)).ToList();
var infoFiles = infos.Select(x => Parser.NormalizePath(x.FullFilePath)).ToList();
return infoFiles.Intersect(chapterFiles).Any();
}

}
20 changes: 8 additions & 12 deletions API/Helpers/Builders/ChapterBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using API.Entities;
using API.Entities.Enums;
using API.Services.Tasks.Scanner.Parser;
Expand All @@ -17,7 +18,7 @@ public ChapterBuilder(string number, string? range=null)
{
_chapter = new Chapter()
{
Range = string.IsNullOrEmpty(range) ? number : range,
Range = string.IsNullOrEmpty(range) ? number : Parser.RemoveExtensionIfSupported(range),
Title = string.IsNullOrEmpty(range) ? number : range,
Number = Parser.MinNumberFromRange(number).ToString(CultureInfo.InvariantCulture),
MinNumber = Parser.MinNumberFromRange(number),
Expand All @@ -32,17 +33,14 @@ public ChapterBuilder(string number, string? range=null)
public static ChapterBuilder FromParserInfo(ParserInfo info)
{
var specialTreatment = info.IsSpecialInfo();
var specialTitle = specialTreatment ? info.Filename : info.Chapters;
var specialTitle = specialTreatment ? Parser.RemoveExtensionIfSupported(info.Filename) : info.Chapters;
var builder = new ChapterBuilder(Parser.DefaultChapter);
// TODO: Come back here and remove this side effect
return builder.WithNumber(specialTreatment ? Parser.DefaultChapter : Parser.MinNumberFromRange(info.Chapters) + string.Empty)

return builder.WithNumber(Parser.RemoveExtensionIfSupported(info.Chapters))
.WithRange(specialTreatment ? info.Filename : info.Chapters)
.WithTitle((specialTreatment && info.Format == MangaFormat.Epub)
? info.Title
: specialTitle)
// NEW
//.WithTitle(string.IsNullOrEmpty(info.Filename) ? specialTitle : info.Filename)
.WithTitle(info.Filename)
.WithIsSpecial(specialTreatment);
}

Expand All @@ -53,7 +51,7 @@ public ChapterBuilder WithId(int id)
}


public ChapterBuilder WithNumber(string number)
private ChapterBuilder WithNumber(string number)
{
_chapter.Number = number;
_chapter.MinNumber = Parser.MinNumberFromRange(number);
Expand All @@ -79,11 +77,9 @@ public ChapterBuilder WithStoryArcNumber(string number)
return this;
}

private ChapterBuilder WithRange(string range)
public ChapterBuilder WithRange(string range)
{
_chapter.Range = range;
// TODO: HACK: Overriding range
_chapter.Range = _chapter.GetNumberTitle();
_chapter.Range = Parser.RemoveExtensionIfSupported(range);
return this;
}

Expand Down
3 changes: 2 additions & 1 deletion API/Helpers/Builders/MangaFileBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.IO;
using API.Entities;
using API.Entities.Enums;
using API.Services.Tasks.Scanner.Parser;

namespace API.Helpers.Builders;

Expand All @@ -19,7 +20,7 @@ public MangaFileBuilder(string filePath, MangaFormat format, int pages = 0)
Pages = pages,
LastModified = File.GetLastWriteTime(filePath),
LastModifiedUtc = File.GetLastWriteTimeUtc(filePath),
FileName = Path.GetFileNameWithoutExtension(filePath)
FileName = Parser.RemoveExtensionIfSupported(filePath)
};
}

Expand Down
1 change: 1 addition & 0 deletions API/Services/MetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ private Task<bool> UpdateChapterCoverImage(Chapter chapter, bool forceUpdate, En
chapter.CoverImage = _readingItemService.GetCoverImage(firstFile.FilePath,
ImageService.GetChapterFormat(chapter.Id, chapter.VolumeId), firstFile.Format, encodeFormat, coverImageSize);
_unitOfWork.ChapterRepository.Update(chapter);

_updateEvents.Add(MessageFactory.CoverUpdateEvent(chapter.Id, MessageFactoryEntityTypes.Chapter));
return Task.FromResult(true);
}
Expand Down
Loading

0 comments on commit fc87dba

Please sign in to comment.