Add one name dedupe function and use it for parsed names and metadata.json

This commit is contained in:
mikiher committed 2026-11-01 09:10:45 +02:00
1 parent 616c8ba152
commit f1f57d6595
3 files changed
+41 -5

No files matched your search

@@ -1,5 +1,6 @@
const Logger = require('../../Logger')
const parseSeriesString = require('../parsers/parseSeriesString')
const { dedupeNames } = require('../parsers/parseNameString')
const mediaTypeKeys = {
book: {
@@ -140,8 +141,7 @@ function validateMetadataValue(key, value, expectedType) {
return undefined
}
const cleanedArray = value.filter((t) => typeof t === 'string')
return [...new Set(cleanedArray.map((t) => t.trim()).filter((t) => t))]
return dedupeNames(value)
}
Logger.warn(`[abmetadataGenerator] Unknown expected type "${expectedType}" for key "${key}"`)
+24 -2
View File
@@ -35,6 +35,28 @@ module.exports.nameToLastFirst = (firstLast) => {
return `${nameObj.last_name}, ${nameObj.first_name}`
}
/**
* Trim names, drop blanks, and drop exact repeats. The first spelling is kept.
* Callers that build bookAuthors rows should use this instead of deduping per metadata source.
*
* @param {string[]} names
* @returns {string[]}
*/
function dedupeNames(names) {
if (!Array.isArray(names)) return []
const seen = new Set()
const deduped = []
for (const name of names) {
if (typeof name !== 'string') continue
const trimmed = name.trim()
if (!trimmed || seen.has(trimmed)) continue
seen.add(trimmed)
deduped.push(trimmed)
}
return deduped
}
module.exports.dedupeNames = dedupeNames
/**
* Parses a name string into an array of names
*
@@ -62,7 +84,7 @@ module.exports.parse = (nameString) => {
// If names are in Chinese,Japanese and Korean languages, return as is.
if (/[\u4e00-\u9fff\u3040-\u30ff\u31f0-\u31ff]/.test(splitNames[0])) {
return {
names: splitNames
names: dedupeNames(splitNames)
}
}
@@ -102,7 +124,7 @@ module.exports.parse = (nameString) => {
names = names.filter((n) => n.first_name || n.last_name)
// Set name strings and remove duplicates
const namesArray = [...new Set(names.map((a) => (a.first_name ? `${a.first_name} ${a.last_name}` : a.last_name)))]
const namesArray = dedupeNames(names.map((a) => (a.first_name ? `${a.first_name} ${a.last_name}` : a.last_name)))
return {
names: namesArray // Array of first last
@@ -1,6 +1,6 @@
const chai = require('chai')
const expect = chai.expect
const { parse, nameToLastFirst } = require('../../../../server/utils/parsers/parseNameString')
const { parse, nameToLastFirst, dedupeNames } = require('../../../../server/utils/parsers/parseNameString')
describe('parseNameString', () => {
describe('parse', () => {
@@ -80,6 +80,20 @@ describe('parseNameString', () => {
})
})
describe('dedupeNames', () => {
it('trims, drops blanks, and keeps the first spelling of an exact repeat', () => {
expect(dedupeNames([' Stephen King ', 'Stephen King', '', ' ', 'stephen king'])).to.deep.equal(['Stephen King', 'stephen king'])
})
it('preserves order and ignores non-strings', () => {
expect(dedupeNames(['Amy Yao', null, 'Amy Yao', 3, 'Raymond Chandler'])).to.deep.equal(['Amy Yao', 'Raymond Chandler'])
})
it('returns an empty array for non-arrays', () => {
expect(dedupeNames(null)).to.deep.equal([])
})
})
describe('nameToLastFirst', () => {
it('converts First Last to Last, First format', () => {
const result = nameToLastFirst('John Smith')