Fix fetchSeries so it deduplicates returned series

This commit is contained in:
mikiher 2024-07-12 12:42:42 +03:00
parent f0a1ea4d6d
commit c0004dd532

View File

@ -5,7 +5,7 @@ function parseCreators(metadata) {
if (!metadata['dc:creator']) return null if (!metadata['dc:creator']) return null
const creators = metadata['dc:creator'] const creators = metadata['dc:creator']
if (!creators.length) return null if (!creators.length) return null
return creators.map(c => { return creators.map((c) => {
if (typeof c !== 'object' || !c['$'] || !c['_']) return false if (typeof c !== 'object' || !c['$'] || !c['_']) return false
return { return {
value: c['_'], value: c['_'],
@ -17,7 +17,7 @@ function parseCreators(metadata) {
function fetchCreators(creators, role) { function fetchCreators(creators, role) {
if (!creators?.length) return null if (!creators?.length) return null
return [...new Set(creators.filter(c => c.role === role && c.value).map(c => c.value))] return [...new Set(creators.filter((c) => c.role === role && c.value).map((c) => c.value))]
} }
function fetchTagString(metadata, tag) { function fetchTagString(metadata, tag) {
@ -62,14 +62,14 @@ function fetchPublisher(metadata) {
function fetchISBN(metadata) { function fetchISBN(metadata) {
if (!metadata['dc:identifier'] || !metadata['dc:identifier'].length) return null if (!metadata['dc:identifier'] || !metadata['dc:identifier'].length) return null
const identifiers = metadata['dc:identifier'] const identifiers = metadata['dc:identifier']
const isbnObj = identifiers.find(i => i['$'] && i['$']['opf:scheme'] === 'ISBN') const isbnObj = identifiers.find((i) => i['$'] && i['$']['opf:scheme'] === 'ISBN')
return isbnObj ? isbnObj['_'] || null : null return isbnObj ? isbnObj['_'] || null : null
} }
function fetchASIN(metadata) { function fetchASIN(metadata) {
if (!metadata['dc:identifier'] || !metadata['dc:identifier'].length) return null if (!metadata['dc:identifier'] || !metadata['dc:identifier'].length) return null
const identifiers = metadata['dc:identifier'] const identifiers = metadata['dc:identifier']
const asinObj = identifiers.find(i => i['$'] && i['$']['opf:scheme'] === 'ASIN') const asinObj = identifiers.find((i) => i['$'] && i['$']['opf:scheme'] === 'ASIN')
return asinObj ? asinObj['_'] || null : null return asinObj ? asinObj['_'] || null : null
} }
@ -92,7 +92,7 @@ function fetchDescription(metadata) {
function fetchGenres(metadata) { function fetchGenres(metadata) {
if (!metadata['dc:subject'] || !metadata['dc:subject'].length) return [] if (!metadata['dc:subject'] || !metadata['dc:subject'].length) return []
return [...new Set(metadata['dc:subject'].filter(g => g && typeof g === 'string'))] return [...new Set(metadata['dc:subject'].filter((g) => g && typeof g === 'string'))]
} }
function fetchLanguage(metadata) { function fetchLanguage(metadata) {
@ -116,20 +116,24 @@ function fetchSeries(metadataMeta) {
// If one series was found with no series_index then check if any series_index meta can be found // If one series was found with no series_index then check if any series_index meta can be found
// this is to support when calibre:series_index is not directly underneath calibre:series // this is to support when calibre:series_index is not directly underneath calibre:series
if (result.length === 1 && !result[0].sequence) { if (result.length === 1 && !result[0].sequence) {
const seriesIndexMeta = metadataMeta.find(m => m.$?.name === 'calibre:series_index' && m.$.content?.trim()) const seriesIndexMeta = metadataMeta.find((m) => m.$?.name === 'calibre:series_index' && m.$.content?.trim())
if (seriesIndexMeta) { if (seriesIndexMeta) {
result[0].sequence = seriesIndexMeta.$.content.trim() result[0].sequence = seriesIndexMeta.$.content.trim()
} }
} }
return result
// Remove duplicates
const dedupedResult = result.filter((se, idx) => result.findIndex((s) => s.name === se.name) === idx)
return dedupedResult
} }
function fetchNarrators(creators, metadata) { function fetchNarrators(creators, metadata) {
const narrators = fetchCreators(creators, 'nrt') const narrators = fetchCreators(creators, 'nrt')
if (narrators?.length) return narrators if (narrators?.length) return narrators
try { try {
const narratorsJSON = JSON.parse(fetchTagString(metadata.meta, "calibre:user_metadata:#narrators").replace(/"/g, '"')) const narratorsJSON = JSON.parse(fetchTagString(metadata.meta, 'calibre:user_metadata:#narrators').replace(/"/g, '"'))
return narratorsJSON["#value#"] return narratorsJSON['#value#']
} catch { } catch {
return null return null
} }
@ -137,7 +141,7 @@ function fetchNarrators(creators, metadata) {
function fetchTags(metadata) { function fetchTags(metadata) {
if (!metadata['dc:tag'] || !metadata['dc:tag'].length) return [] if (!metadata['dc:tag'] || !metadata['dc:tag'].length) return []
return [...new Set(metadata['dc:tag'].filter(tag => tag && typeof tag === 'string'))] return [...new Set(metadata['dc:tag'].filter((tag) => tag && typeof tag === 'string'))]
} }
function stripPrefix(str) { function stripPrefix(str) {
@ -147,7 +151,7 @@ function stripPrefix(str) {
module.exports.parseOpfMetadataJson = (json) => { module.exports.parseOpfMetadataJson = (json) => {
// Handle <package ...> or with prefix <ns0:package ...> // Handle <package ...> or with prefix <ns0:package ...>
const packageKey = Object.keys(json).find(key => stripPrefix(key) === 'package') const packageKey = Object.keys(json).find((key) => stripPrefix(key) === 'package')
if (!packageKey) return null if (!packageKey) return null
const prefix = packageKey.split(':').shift() const prefix = packageKey.split(':').shift()
let metadata = prefix ? json[packageKey][`${prefix}:metadata`] || json[packageKey].metadata : json[packageKey].metadata let metadata = prefix ? json[packageKey][`${prefix}:metadata`] || json[packageKey].metadata : json[packageKey].metadata
@ -170,8 +174,8 @@ module.exports.parseOpfMetadataJson = (json) => {
} }
const creators = parseCreators(metadata) const creators = parseCreators(metadata)
const authors = (fetchCreators(creators, 'aut') || []).map(au => au?.trim()).filter(au => au) const authors = (fetchCreators(creators, 'aut') || []).map((au) => au?.trim()).filter((au) => au)
const narrators = (fetchNarrators(creators, metadata) || []).map(nrt => nrt?.trim()).filter(nrt => nrt) const narrators = (fetchNarrators(creators, metadata) || []).map((nrt) => nrt?.trim()).filter((nrt) => nrt)
return { return {
title: fetchTitle(metadata), title: fetchTitle(metadata),
subtitle: fetchSubtitle(metadata), subtitle: fetchSubtitle(metadata),
@ -193,4 +197,4 @@ module.exports.parseOpfMetadataXML = async (xml) => {
const json = await xmlToJSON(xml) const json = await xmlToJSON(xml)
if (!json) return null if (!json) return null
return this.parseOpfMetadataJson(json) return this.parseOpfMetadataJson(json)
} }