Keep iTunes author credentials attached to the name

This commit is contained in:
mikiher committed 2026-11-02 10:04:19 +02:00
1 parent ce41ce489c
commit 087099faa3
2 files changed
+103 -5

No files matched your search

+50 -5
View File
@@ -27,6 +27,55 @@ const htmlSanitizer = require('../utils/htmlSanitizer')
* @property {boolean} explicit * @property {boolean} explicit
*/ */
/**
* Split a list of authors on commas. A piece with no space is a credential and is glued onto the previous name.
*
* @param {string} text
* @returns {string[]}
*/
function parseAuthorPieces(text) {
const authors = []
for (const piece of (text || '').split(',')) {
const name = piece.trim()
if (!name) continue
if (!name.includes(' ') && authors.length) {
authors[authors.length - 1] = `${authors[authors.length - 1]} ${name}`
} else {
authors.push(name)
}
}
return authors
}
function stripCommasFromName(name) {
return (name || '').replace(/,/g, '').replace(/\s+/g, ' ').trim()
}
/**
* Apple lists authors as "Name1, Name2 & Name3", but a comma can also sit inside one name ("Rick Hanson, PhD").
* A comma-separated piece with no space is treated as a credential and glued onto the previous name.
* The text after the last " & " is a single author, so commas there are removed.
* @see https://github.com/advplyr/audiobookshelf/issues/1022
* @see https://github.com/advplyr/audiobookshelf/issues/2661
*
* @param {string} artistName
* @returns {string}
*/
function cleanAuthor(artistName) {
const raw = (artistName || '').trim()
if (!raw) return ''
const lastAmpIndex = raw.lastIndexOf(' & ')
if (lastAmpIndex === -1) {
return stripCommasFromName(raw)
}
const authors = parseAuthorPieces(raw.slice(0, lastAmpIndex))
const lastAuthor = stripCommasFromName(raw.slice(lastAmpIndex + 3))
if (lastAuthor) authors.push(lastAuthor)
return authors.join(', ')
}
class iTunes { class iTunes {
#responseTimeout = 10000 #responseTimeout = 10000
@@ -103,15 +152,11 @@ class iTunes {
} }
cleanAudiobook(data) { cleanAudiobook(data) {
// artistName can be "Name1, Name2 & Name3" so we refactor this to "Name1, Name2, Name3"
// see: https://github.com/advplyr/audiobookshelf/issues/1022
const author = (data.artistName || '').split(' & ').join(', ')
return { return {
id: data.collectionId, id: data.collectionId,
artistId: data.artistId, artistId: data.artistId,
title: data.collectionName, title: data.collectionName,
author, author: cleanAuthor(data.artistName),
description: data.description || null, description: data.description || null,
publishedYear: data.releaseDate ? data.releaseDate.split('-')[0] : null, publishedYear: data.releaseDate ? data.releaseDate.split('-')[0] : null,
genres: data.primaryGenreName ? [data.primaryGenreName] : null, genres: data.primaryGenreName ? [data.primaryGenreName] : null,
+53
View File
@@ -0,0 +1,53 @@
const iTunes = require('../../../server/providers/iTunes')
const { expect } = require('chai')
describe('iTunes', () => {
let itunes
beforeEach(() => {
itunes = new iTunes()
})
describe('cleanAudiobook', () => {
function authorFrom(artistName) {
return itunes.cleanAudiobook({ artistName }).author
}
it('should return an empty string if artistName is missing', () => {
expect(authorFrom()).to.equal('')
expect(authorFrom('')).to.equal('')
})
it('should keep a single author without commas', () => {
expect(authorFrom('Joy Fielding')).to.equal('Joy Fielding')
})
it('should strip commas from a single author with a credential', () => {
expect(authorFrom('Rick Hanson, PhD')).to.equal('Rick Hanson PhD')
})
it('should split two authors joined by an ampersand', () => {
expect(authorFrom('Name1 & Name2')).to.equal('Name1, Name2')
})
it('should split three authors using commas and an ampersand', () => {
expect(authorFrom('Keltie Knight, Becca Tobin & Jac Vanek')).to.equal('Keltie Knight, Becca Tobin, Jac Vanek')
})
it('should glue a one-word credential onto the previous author before the ampersand', () => {
expect(authorFrom('Rick Hanson, PhD & Jane Doe')).to.equal('Rick Hanson PhD, Jane Doe')
})
it('should glue several one-word credentials in a row', () => {
expect(authorFrom('Rick Hanson, PhD, MD & Jane Doe')).to.equal('Rick Hanson PhD MD, Jane Doe')
})
it('should strip commas from the last author', () => {
expect(authorFrom('Rick Hanson & Jane Doe, PhD')).to.equal('Rick Hanson, Jane Doe PhD')
})
it('should glue credentials before the ampersand and strip commas from the last author', () => {
expect(authorFrom('Rick Hanson, PhD & Jane Doe, PhD')).to.equal('Rick Hanson PhD, Jane Doe PhD')
})
})
})