diff --git a/server/utils/parsers/parseOpfMetadata.js b/server/utils/parsers/parseOpfMetadata.js index a5419601..5737a5da 100644 --- a/server/utils/parsers/parseOpfMetadata.js +++ b/server/utils/parsers/parseOpfMetadata.js @@ -5,7 +5,7 @@ function parseCreators(metadata) { if (!metadata['dc:creator']) return null const creators = metadata['dc:creator'] if (!creators.length) return null - return creators.map(c => { + return creators.map((c) => { if (typeof c !== 'object' || !c['$'] || !c['_']) return false return { value: c['_'], @@ -17,7 +17,7 @@ function parseCreators(metadata) { function fetchCreators(creators, role) { 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) { @@ -62,14 +62,14 @@ function fetchPublisher(metadata) { function fetchISBN(metadata) { if (!metadata['dc:identifier'] || !metadata['dc:identifier'].length) return null 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 } function fetchASIN(metadata) { if (!metadata['dc:identifier'] || !metadata['dc:identifier'].length) return null 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 } @@ -92,7 +92,7 @@ function fetchDescription(metadata) { function fetchGenres(metadata) { 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) { @@ -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 // this is to support when calibre:series_index is not directly underneath calibre:series 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) { 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) { const narrators = fetchCreators(creators, 'nrt') if (narrators?.length) return narrators try { - const narratorsJSON = JSON.parse(fetchTagString(metadata.meta, "calibre:user_metadata:#narrators").replace(/"/g, '"')) - return narratorsJSON["#value#"] + const narratorsJSON = JSON.parse(fetchTagString(metadata.meta, 'calibre:user_metadata:#narrators').replace(/"/g, '"')) + return narratorsJSON['#value#'] } catch { return null } @@ -137,7 +141,7 @@ function fetchNarrators(creators, metadata) { function fetchTags(metadata) { 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) { @@ -147,7 +151,7 @@ function stripPrefix(str) { module.exports.parseOpfMetadataJson = (json) => { // Handle or with prefix - const packageKey = Object.keys(json).find(key => stripPrefix(key) === 'package') + const packageKey = Object.keys(json).find((key) => stripPrefix(key) === 'package') if (!packageKey) return null const prefix = packageKey.split(':').shift() 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 authors = (fetchCreators(creators, 'aut') || []).map(au => au?.trim()).filter(au => au) - const narrators = (fetchNarrators(creators, metadata) || []).map(nrt => nrt?.trim()).filter(nrt => nrt) + const authors = (fetchCreators(creators, 'aut') || []).map((au) => au?.trim()).filter((au) => au) + const narrators = (fetchNarrators(creators, metadata) || []).map((nrt) => nrt?.trim()).filter((nrt) => nrt) return { title: fetchTitle(metadata), subtitle: fetchSubtitle(metadata), @@ -193,4 +197,4 @@ module.exports.parseOpfMetadataXML = async (xml) => { const json = await xmlToJSON(xml) if (!json) return null return this.parseOpfMetadataJson(json) -} \ No newline at end of file +}