Merge pull request #230 from GooglyBlox/feat/full-artist-metadata

feat(metadata): Add all artists to metadata
This commit is contained in:
Eduard Prigoana 2026-02-22 17:46:45 +02:00 committed by GitHub
commit 4f35e319b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -5,6 +5,33 @@ const DEFAULT_TITLE = 'Unknown Title';
const DEFAULT_ARTIST = 'Unknown Artist'; const DEFAULT_ARTIST = 'Unknown Artist';
const DEFAULT_ALBUM = 'Unknown Album'; const DEFAULT_ALBUM = 'Unknown Album';
/**
* Builds a full artist string by combining the track's listed artists
* with any featured artists parsed from the title (feat./with).
*/
function getFullArtistString(track) {
const knownArtists = Array.isArray(track.artists) && track.artists.length > 0
? track.artists.map((a) => (typeof a === 'string' ? a : a.name) || '').filter(Boolean)
: track.artist?.name ? [track.artist.name] : [];
// Parse featured artists from title, e.g. "Song (feat. A, B & C)" or "(with X & Y)"
// Note: splitting on '&' may incorrectly fragment compound artist names like "Simon & Garfunkel".
const featPattern = /\(\s*(?:feat\.?|ft\.?|with)\s+(.+?)\s*\)/gi;
const allFeatArtists = [...(track.title?.matchAll(featPattern) ?? [])]
.flatMap((m) => m[1].split(/\s*[,&]\s*/).map((s) => s.trim()).filter(Boolean));
if (allFeatArtists.length > 0) {
const knownLower = new Set(knownArtists.map((n) => n.toLowerCase()));
for (const feat of allFeatArtists) {
if (!knownLower.has(feat.toLowerCase())) {
knownArtists.push(feat);
knownLower.add(feat.toLowerCase());
}
}
}
return knownArtists.join('; ') || null;
}
/** /**
* Adds metadata tags to audio files (FLAC or M4A) * Adds metadata tags to audio files (FLAC or M4A)
* @param {Blob} audioBlob - The audio file blob * @param {Blob} audioBlob - The audio file blob
@ -550,8 +577,9 @@ function createVorbisCommentBlock(track) {
if (track.title) { if (track.title) {
comments.push(['TITLE', track.title]); comments.push(['TITLE', track.title]);
} }
if (track.artist?.name) { const artistStr = getFullArtistString(track);
comments.push(['ARTIST', track.artist.name]); if (artistStr) {
comments.push(['ARTIST', artistStr]);
} }
if (track.album?.title) { if (track.album?.title) {
comments.push(['ALBUM', track.album.title]); comments.push(['ALBUM', track.album.title]);
@ -910,7 +938,7 @@ function createMp4MetadataAtoms(track) {
const tags = { const tags = {
'©nam': track.title || DEFAULT_TITLE, '©nam': track.title || DEFAULT_TITLE,
'©ART': track.artist?.name || DEFAULT_ARTIST, '©ART': getFullArtistString(track) || DEFAULT_ARTIST,
'©alb': track.album?.title || DEFAULT_ALBUM, '©alb': track.album?.title || DEFAULT_ALBUM,
aART: track.album?.artist?.name || track.artist?.name || DEFAULT_ARTIST, aART: track.album?.artist?.name || track.artist?.name || DEFAULT_ARTIST,
}; };