Feature/misc (#1234)

* Fixed a bug where publication status could show as filled in when total number is 0 but there is a max count.

Add ComicInfo support for LocalizedSeries which will populate a Series LocalizedName.

Fixed an issue in tag constraint issues.

* Hooked in LocalizedSeries tag into merge step in scanner.

* Hooked in LocalizedSeries from ComicInfo into Kavita and also use it to help during merge phase to avoid 2 different series, if one file is using the name of the localized series.

* Reduced some extra string creation and updated epub library to ignore bad ToCs.

* Bumped dependencies to latest. When an epub doesn't have a dc:date with publication event type, default back to just a normal dc:date tag.

* Fixed a bug where webtoon reader would error out on first load due to how we passed the function to the reader

* Reverted the centering code
This commit is contained in:
Joseph Milazzo 2022-04-28 16:50:31 -05:00 committed by GitHub
parent 0eb3d74ff9
commit 1e51e39f66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 114 additions and 66 deletions

View file

@ -20,6 +20,7 @@ using Microsoft.IO;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using VersOne.Epub;
using VersOne.Epub.Options;
using Image = SixLabors.ImageSharp.Image;
namespace API.Services
@ -59,6 +60,13 @@ namespace API.Services
private readonly StylesheetParser _cssParser = new ();
private static readonly RecyclableMemoryStreamManager StreamManager = new ();
private const string CssScopeClass = ".book-content";
public static readonly EpubReaderOptions BookReaderOptions = new()
{
PackageReaderOptions = new PackageReaderOptions()
{
IgnoreMissingToc = true
}
};
public BookService(ILogger<BookService> logger, IDirectoryService directoryService, IImageService imageService)
{
@ -383,10 +391,14 @@ namespace API.Services
try
{
using var epubBook = EpubReader.OpenBook(filePath);
using var epubBook = EpubReader.OpenBook(filePath, BookReaderOptions);
var publicationDate =
epubBook.Schema.Package.Metadata.Dates.FirstOrDefault(date => date.Event == "publication")?.Date;
if (string.IsNullOrEmpty(publicationDate))
{
publicationDate = epubBook.Schema.Package.Metadata.Dates.FirstOrDefault()?.Date;
}
var info = new ComicInfo()
{
Summary = epubBook.Schema.Package.Metadata.Description,
@ -450,7 +462,7 @@ namespace API.Services
return docReader.GetPageCount();
}
using var epubBook = EpubReader.OpenBook(filePath);
using var epubBook = EpubReader.OpenBook(filePath, BookReaderOptions);
return epubBook.Content.Html.Count;
}
catch (Exception ex)
@ -504,7 +516,7 @@ namespace API.Services
try
{
using var epubBook = EpubReader.OpenBook(filePath);
using var epubBook = EpubReader.OpenBook(filePath, BookReaderOptions);
// <meta content="The Dark Tower" name="calibre:series"/>
// <meta content="Wolves of the Calla" name="calibre:title_sort"/>
@ -669,8 +681,7 @@ namespace API.Services
return GetPdfCoverImage(fileFilePath, fileName, outputDirectory);
}
using var epubBook = EpubReader.OpenBook(fileFilePath);
using var epubBook = EpubReader.OpenBook(fileFilePath, BookReaderOptions);
try
{

View file

@ -254,7 +254,6 @@ public class SeriesService : ISeriesService
// At this point, all tags that aren't in dto have been removed.
foreach (var tagTitle in tags.Select(t => t.Title))
{
// This should be normalized name
var normalizedTitle = Parser.Parser.Normalize(tagTitle);
var existingTag = allTags.SingleOrDefault(t => t.NormalizedTitle == normalizedTitle);
if (existingTag != null)
@ -299,10 +298,11 @@ public class SeriesService : ISeriesService
// At this point, all tags that aren't in dto have been removed.
foreach (var tagTitle in tags.Select(t => t.Title))
{
var existingTag = allTags.SingleOrDefault(t => t.Title == tagTitle);
var normalizedTitle = Parser.Parser.Normalize(tagTitle);
var existingTag = allTags.SingleOrDefault(t => t.NormalizedTitle.Equals(normalizedTitle));
if (existingTag != null)
{
if (series.Metadata.Tags.All(t => t.Title != tagTitle))
if (series.Metadata.Tags.All(t => t.NormalizedTitle != normalizedTitle))
{
handleAdd(existingTag);

View file

@ -126,6 +126,11 @@ namespace API.Services.Tasks.Scanner
{
info.SeriesSort = info.ComicInfo.SeriesSort.Trim();
}
if (!string.IsNullOrEmpty(info.ComicInfo.LocalizedSeries))
{
info.LocalizedSeries = info.ComicInfo.LocalizedSeries.Trim();
}
}
TrackSeries(info);
@ -144,13 +149,16 @@ namespace API.Services.Tasks.Scanner
// Check if normalized info.Series already exists and if so, update info to use that name instead
info.Series = MergeName(info);
var normalizedSeries = Parser.Parser.Normalize(info.Series);
var normalizedLocalizedSeries = Parser.Parser.Normalize(info.LocalizedSeries);
var existingKey = _scannedSeries.Keys.FirstOrDefault(ps =>
ps.Format == info.Format && ps.NormalizedName == Parser.Parser.Normalize(info.Series));
ps.Format == info.Format && (ps.NormalizedName == normalizedSeries
|| ps.NormalizedName == normalizedLocalizedSeries));
existingKey ??= new ParsedSeries()
{
Format = info.Format,
Name = info.Series,
NormalizedName = Parser.Parser.Normalize(info.Series)
NormalizedName = normalizedSeries
};
_scannedSeries.AddOrUpdate(existingKey, new List<ParserInfo>() {info}, (_, oldValue) =>
@ -174,8 +182,11 @@ namespace API.Services.Tasks.Scanner
public string MergeName(ParserInfo info)
{
var normalizedSeries = Parser.Parser.Normalize(info.Series);
var normalizedLocalSeries = Parser.Parser.Normalize(info.LocalizedSeries);
var existingName =
_scannedSeries.SingleOrDefault(p => Parser.Parser.Normalize(p.Key.NormalizedName) == normalizedSeries && p.Key.Format == info.Format)
_scannedSeries.SingleOrDefault(p =>
(Parser.Parser.Normalize(p.Key.NormalizedName) == normalizedSeries ||
Parser.Parser.Normalize(p.Key.NormalizedName) == normalizedLocalSeries) && p.Key.Format == info.Format)
.Key;
if (existingName != null && !string.IsNullOrEmpty(existingName.Name))
{

View file

@ -457,10 +457,14 @@ public class ScannerService : IScannerService
if (existingSeries != null) continue;
var s = DbFactory.Series(infos[0].Series);
if (!string.IsNullOrEmpty(infos[0].SeriesSort))
if (!s.SortNameLocked && !string.IsNullOrEmpty(infos[0].SeriesSort))
{
s.SortName = infos[0].SeriesSort;
}
if (!s.LocalizedNameLocked && !string.IsNullOrEmpty(infos[0].LocalizedSeries))
{
s.LocalizedName = infos[0].LocalizedSeries;
}
s.Format = key.Format;
s.LibraryId = library.Id; // We have to manually set this since we aren't adding the series to the Library's series.
newSeries.Add(s);
@ -529,6 +533,13 @@ public class ScannerService : IScannerService
}
}
// parsedInfos[0] is not the first volume or chapter. We need to find it
var localizedSeries = parsedInfos.Select(p => p.LocalizedSeries).FirstOrDefault(p => !string.IsNullOrEmpty(p));
if (!series.LocalizedNameLocked && !string.IsNullOrEmpty(localizedSeries))
{
series.LocalizedName = localizedSeries;
}
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Ended, series.Name));
UpdateSeriesMetadata(series, allPeople, allGenres, allTags, library.Type);