From e6aa7aecbbb4ce635b1591ebdd3305acd69aa27a Mon Sep 17 00:00:00 2001 From: AshleyDeo <35739765+AshleyDeo@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:44:48 -0400 Subject: [PATCH 1/2] Update opf and add isbn Reads all authors for multi-author book. Add google books id from opf Add ISBN as External Id. Uses WorldCat.org as external link --- .../Providers/ISBNExternalId.cs | 26 +++++++++++++++++++ .../Providers/OpfReader.cs | 21 +++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 Jellyfin.Plugin.Bookshelf/Providers/ISBNExternalId.cs diff --git a/Jellyfin.Plugin.Bookshelf/Providers/ISBNExternalId.cs b/Jellyfin.Plugin.Bookshelf/Providers/ISBNExternalId.cs new file mode 100644 index 00000000..3ea08d92 --- /dev/null +++ b/Jellyfin.Plugin.Bookshelf/Providers/ISBNExternalId.cs @@ -0,0 +1,26 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; + +namespace Jellyfin.Plugin.Bookshelf.Providers +{ + /// + public class ISBNExternalId : IExternalId + { + /// + public string ProviderName => "ISBN"; + + /// + public string Key => "ISBN"; + + /// + public ExternalIdMediaType? Type => null; + + /// + public string? UrlFormatString => "https://search.worldcat.org/search?q=bn:{0}"; + + /// + public bool Supports(IHasProviderIds item) => item is Book; + } +} diff --git a/Jellyfin.Plugin.Bookshelf/Providers/OpfReader.cs b/Jellyfin.Plugin.Bookshelf/Providers/OpfReader.cs index 3768242f..7dc5abec 100644 --- a/Jellyfin.Plugin.Bookshelf/Providers/OpfReader.cs +++ b/Jellyfin.Plugin.Bookshelf/Providers/OpfReader.cs @@ -104,11 +104,7 @@ public MetadataResult ReadOpfData( var book = CreateBookFromOpf(); var bookResult = new MetadataResult { Item = book, HasMetadata = true }; - ReadStringInto("//dc:creator", author => - { - var person = new PersonInfo { Name = author, Type = PersonKind.Author }; - bookResult.AddPerson(person); - }); + FindAuthors(bookResult); ReadStringInto("//dc:language", language => bookResult.ResultLanguage = language); @@ -126,6 +122,7 @@ private Book CreateBookFromOpf() ReadStringInto("//dc:publisher", publisher => book.AddStudio(publisher)); ReadStringInto("//dc:identifier[@opf:scheme='ISBN']", isbn => book.SetProviderId("ISBN", isbn)); ReadStringInto("//dc:identifier[@opf:scheme='AMAZON']", amazon => book.SetProviderId("Amazon", amazon)); + ReadStringInto("//dc:identifier[@opf:scheme='GOOGLE']", google => book.SetProviderId("GoogleBooks", google)); ReadStringInto("//dc:date", date => { @@ -222,6 +219,20 @@ private string FindMainTitle() return titleSort; } + private void FindAuthors(MetadataResult book) + { + var resultElement = _document.SelectNodes("//dc:creator[@opf:role='aut']", _namespaceManager); + if (resultElement != null && resultElement.Count > 0) + { + foreach (XmlElement author in resultElement) + { + var authorName = author.InnerText; + var person = new PersonInfo { Name = authorName, Type = PersonKind.Author }; + book.AddPerson(person); + } + } + } + private void ReadStringInto(string xPath, Action commitResult) { var resultElement = _document.SelectSingleNode(xPath, _namespaceManager); From c0d2177afd61b41b11d60ff432e7e8ffb0f65b39 Mon Sep 17 00:00:00 2001 From: AshleyDeo <35739765+AshleyDeo@users.noreply.github.com> Date: Tue, 23 Jul 2024 21:07:25 -0400 Subject: [PATCH 2/2] Parse opf roles --- .../Providers/OpfReader.cs | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/Jellyfin.Plugin.Bookshelf/Providers/OpfReader.cs b/Jellyfin.Plugin.Bookshelf/Providers/OpfReader.cs index 7dc5abec..a7b6dfff 100644 --- a/Jellyfin.Plugin.Bookshelf/Providers/OpfReader.cs +++ b/Jellyfin.Plugin.Bookshelf/Providers/OpfReader.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Data; using System.Globalization; using System.IO; using System.Linq; @@ -221,18 +223,48 @@ private string FindMainTitle() private void FindAuthors(MetadataResult book) { - var resultElement = _document.SelectNodes("//dc:creator[@opf:role='aut']", _namespaceManager); + var resultElement = _document.SelectNodes("//dc:creator", _namespaceManager); if (resultElement != null && resultElement.Count > 0) { - foreach (XmlElement author in resultElement) + foreach (XmlElement creator in resultElement) { - var authorName = author.InnerText; - var person = new PersonInfo { Name = authorName, Type = PersonKind.Author }; + var creatorName = creator.InnerText; + string? role = creator.GetAttribute("opf:role"); + var person = new PersonInfo { Name = creatorName, Type = GetRole(role) }; book.AddPerson(person); } } } + private PersonKind GetRole(string role) + { + switch (role) + { + case "arr": + return PersonKind.Arranger; + case "art": + return PersonKind.Artist; + case "aut": + case "aqt": + case "aft": + case "aui": + default: + return PersonKind.Author; + case "edt": + return PersonKind.Editor; + case "ill": + return PersonKind.Illustrator; + case "lyr": + return PersonKind.Lyricist; + case "mus": + return PersonKind.AlbumArtist; + case "oth": + return PersonKind.Unknown; + case "trl": + return PersonKind.Translator; + } + } + private void ReadStringInto(string xPath, Action commitResult) { var resultElement = _document.SelectSingleNode(xPath, _namespaceManager);