From ccb6ac9705e90fe56a6de41d3b01e589ee7fd3b6 Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Sun, 7 May 2023 12:43:21 -0500 Subject: [PATCH] Expanded Metadata for EPUBs (#1965) * Fixed a bug breaking ability to save server settings * Explicitly capture more people roles from Epubs, else fallback to how we do it now. It seems to be getting called twice and 2nd time is overriding data. Not sure why * Refactored the code to clean it up * Added support for generating collections or reading list based on dc:title and collection title-type with an optional display-seq. * ReadingList/Collection support can't be done until VersOne supports. https://github.com/vers-one/EpubReader/issues/81 * Double include author for epub parsing and let the People code handle removing duplicates. --- API/Services/BookService.cs | 81 +++++++++++++++++++++++++++++- API/Services/ReadingItemService.cs | 1 + 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/API/Services/BookService.cs b/API/Services/BookService.cs index 205fcde94..cfe14eedd 100644 --- a/API/Services/BookService.cs +++ b/API/Services/BookService.cs @@ -25,6 +25,7 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using VersOne.Epub; using VersOne.Epub.Options; +using VersOne.Epub.Schema; namespace API.Services; @@ -422,7 +423,6 @@ public class BookService : IBookService var info = new ComicInfo { Summary = epubBook.Schema.Package.Metadata.Description, - Writer = string.Join(",", epubBook.Schema.Package.Metadata.Creators.Select(c => Parser.CleanAuthor(c.Creator))), Publisher = string.Join(",", epubBook.Schema.Package.Metadata.Publishers), Month = month, Day = day, @@ -454,6 +454,7 @@ public class BookService : IBookService break; } + // EPUB 3.2+ only switch (metadataItem.Property) { @@ -466,10 +467,48 @@ public class BookService : IBookService break; case "collection-type": // These look to be genres from https://manual.calibre-ebook.com/sub_groups.html or can be "series" + break; + case "role": + if (!metadataItem.Scheme.Equals("marc:relators")) break; + + var creatorId = metadataItem.Refines.Replace("#", string.Empty); + var person = epubBook.Schema.Package.Metadata.Creators.SingleOrDefault(c => c.Id == creatorId); + if (person == null) break; + + PopulatePerson(metadataItem, info, person); + break; + case "title-type": + break; + // This is currently not possible until VersOne update's to allow EPUB 3 Title to have attributes + if (!metadataItem.Content.Equals("collection")) break; + var titleId = metadataItem.Refines.Replace("#", string.Empty); + var readingListElem = epubBook.Schema.Package.Metadata.MetaItems.FirstOrDefault(item => + item.Name == "dc:title" && item.Id == titleId); + if (readingListElem == null) break; + + var count = epubBook.Schema.Package.Metadata.MetaItems + .FirstOrDefault(item => + item.Property == "display-seq" && item.Refines == metadataItem.Refines); + if (count == null || count.Content == "0") + { + // Treat this as a Collection + info.StoryArc += "," + readingListElem.Content; + } + else + { + // Treat as a reading list + info.AlternateSeries += "," + readingListElem.Content; + info.AlternateNumber += "," + count.Content; + } + break; } } + // Include regular Writer as well, for cases where there is no special tag + info.Writer = string.Join(",", + epubBook.Schema.Package.Metadata.Creators.Select(c => Parser.CleanAuthor(c.Creator))); + var hasVolumeInSeries = !Parser.ParseVolume(info.Title) .Equals(Parser.DefaultVolume); @@ -492,6 +531,46 @@ public class BookService : IBookService return null; } + private static void PopulatePerson(EpubMetadataMeta metadataItem, ComicInfo info, EpubMetadataCreator person) + { + switch (metadataItem.Content) + { + case "art": + case "artist": + info.CoverArtist += AppendAuthor(person); + return; + case "aut": + case "author": + info.Writer += AppendAuthor(person); + return; + case "pbl": + case "publisher": + info.Publisher += AppendAuthor(person); + return; + case "trl": + case "translator": + info.Translator += AppendAuthor(person); + return; + case "edt": + case "editor": + info.Editor += AppendAuthor(person); + return; + case "ill": + case "illustrator": + info.Letterer += AppendAuthor(person); + return; + case "clr": + case "colorist": + info.Colorist += AppendAuthor(person); + return; + } + } + + private static string AppendAuthor(EpubMetadataCreator person) + { + return Parser.CleanAuthor(person.Creator) + ","; + } + private static (int year, int month, int day) GetPublicationDate(string publicationDate) { var dateParsed = DateTime.TryParse(publicationDate, out var date); diff --git a/API/Services/ReadingItemService.cs b/API/Services/ReadingItemService.cs index 1ef67c1ce..7ef4e63ae 100644 --- a/API/Services/ReadingItemService.cs +++ b/API/Services/ReadingItemService.cs @@ -89,6 +89,7 @@ public class ReadingItemService : IReadingItemService } + // This is first time ComicInfo is called info.ComicInfo = GetComicInfo(path); if (info.ComicInfo == null) return info;