music-metadata
Version:
Music metadata parser for Node.js, supporting virtual any audio and tag format.
195 lines • 6.9 kB
JavaScript
import { UINT32_LE } from 'token-types';
import { CommonTagMapper } from '../common/GenericTagMapper.js';
import { CaseInsensitiveTagMap } from '../common/CaseInsensitiveTagMap.js';
import { decodeString } from '../common/Util.js';
/**
* ID3v2.3/ID3v2.4 tag mappings
*/
const id3v24TagMap = {
// id3v2.3
TIT2: 'title',
TPE1: 'artist',
'TXXX:Artists': 'artists',
TPE2: 'albumartist',
TALB: 'album',
TDRV: 'date', // [ 'date', 'year' ] ToDo: improve 'year' mapping
/**
* Original release year
*/
TORY: 'originalyear',
TPOS: 'disk',
TCON: 'genre',
APIC: 'picture',
TCOM: 'composer',
USLT: 'lyrics',
TSOA: 'albumsort',
TSOT: 'titlesort',
TOAL: 'originalalbum',
TSOP: 'artistsort',
TSO2: 'albumartistsort',
TSOC: 'composersort',
TEXT: 'lyricist',
'TXXX:Writer': 'writer',
TPE3: 'conductor',
// 'IPLS:instrument': 'performer:instrument', // ToDo
TPE4: 'remixer',
'IPLS:arranger': 'arranger',
'IPLS:engineer': 'engineer',
'IPLS:producer': 'producer',
'IPLS:DJ-mix': 'djmixer',
'IPLS:mix': 'mixer',
TPUB: 'label',
TIT1: 'grouping',
TIT3: 'subtitle',
TRCK: 'track',
TCMP: 'compilation',
POPM: 'rating',
TBPM: 'bpm',
TMED: 'media',
'TXXX:CATALOGNUMBER': 'catalognumber',
'TXXX:MusicBrainz Album Status': 'releasestatus',
'TXXX:MusicBrainz Album Type': 'releasetype',
/**
* Release country as documented: https://picard.musicbrainz.org/docs/mappings/#cite_note-0
*/
'TXXX:MusicBrainz Album Release Country': 'releasecountry',
/**
* Release country as implemented // ToDo: report
*/
'TXXX:RELEASECOUNTRY': 'releasecountry',
'TXXX:SCRIPT': 'script',
TLAN: 'language',
TCOP: 'copyright',
WCOP: 'license',
TENC: 'encodedby',
TSSE: 'encodersettings',
'TXXX:BARCODE': 'barcode',
'TXXX:ISRC': 'isrc',
TSRC: 'isrc',
'TXXX:ASIN': 'asin',
'TXXX:originalyear': 'originalyear',
'UFID:http://musicbrainz.org': 'musicbrainz_recordingid',
'TXXX:MusicBrainz Release Track Id': 'musicbrainz_trackid',
'TXXX:MusicBrainz Album Id': 'musicbrainz_albumid',
'TXXX:MusicBrainz Artist Id': 'musicbrainz_artistid',
'TXXX:MusicBrainz Album Artist Id': 'musicbrainz_albumartistid',
'TXXX:MusicBrainz Release Group Id': 'musicbrainz_releasegroupid',
'TXXX:MusicBrainz Work Id': 'musicbrainz_workid',
'TXXX:MusicBrainz TRM Id': 'musicbrainz_trmid',
'TXXX:MusicBrainz Disc Id': 'musicbrainz_discid',
'TXXX:ACOUSTID_ID': 'acoustid_id',
'TXXX:Acoustid Id': 'acoustid_id',
'TXXX:Acoustid Fingerprint': 'acoustid_fingerprint',
'TXXX:MusicIP PUID': 'musicip_puid',
'TXXX:MusicMagic Fingerprint': 'musicip_fingerprint',
WOAR: 'website',
// id3v2.4
// ToDo: In same sequence as defined at http://id3.org/id3v2.4.0-frames
TDRC: 'date', // date YYYY-MM-DD
TYER: 'year',
TDOR: 'originaldate',
// 'TMCL:instrument': 'performer:instrument',
'TIPL:arranger': 'arranger',
'TIPL:engineer': 'engineer',
'TIPL:producer': 'producer',
'TIPL:DJ-mix': 'djmixer',
'TIPL:mix': 'mixer',
TMOO: 'mood',
// additional mappings:
SYLT: 'lyrics',
TSST: 'discsubtitle',
TKEY: 'key',
COMM: 'comment',
TOPE: 'originalartist',
// Windows Media Player
'PRIV:AverageLevel': 'averageLevel',
'PRIV:PeakLevel': 'peakLevel',
// Discogs
'TXXX:DISCOGS_ARTIST_ID': 'discogs_artist_id',
'TXXX:DISCOGS_ARTISTS': 'artists',
'TXXX:DISCOGS_ARTIST_NAME': 'artists',
'TXXX:DISCOGS_ALBUM_ARTISTS': 'albumartist',
'TXXX:DISCOGS_CATALOG': 'catalognumber',
'TXXX:DISCOGS_COUNTRY': 'releasecountry',
'TXXX:DISCOGS_DATE': 'originaldate',
'TXXX:DISCOGS_LABEL': 'label',
'TXXX:DISCOGS_LABEL_ID': 'discogs_label_id',
'TXXX:DISCOGS_MASTER_RELEASE_ID': 'discogs_master_release_id',
'TXXX:DISCOGS_RATING': 'discogs_rating',
'TXXX:DISCOGS_RELEASED': 'date',
'TXXX:DISCOGS_RELEASE_ID': 'discogs_release_id',
'TXXX:DISCOGS_VOTES': 'discogs_votes',
'TXXX:CATALOGID': 'catalognumber',
'TXXX:STYLE': 'genre',
'TXXX:REPLAYGAIN_TRACK_PEAK': 'replaygain_track_peak',
'TXXX:REPLAYGAIN_TRACK_GAIN': 'replaygain_track_gain',
'TXXX:REPLAYGAIN_ALBUM_PEAK': 'replaygain_album_peak',
'TXXX:REPLAYGAIN_ALBUM_GAIN': 'replaygain_album_gain',
'TXXX:MP3GAIN_MINMAX': 'replaygain_track_minmax',
'TXXX:MP3GAIN_ALBUM_MINMAX': 'replaygain_album_minmax',
'TXXX:MP3GAIN_UNDO': 'replaygain_undo',
MVNM: 'movement',
MVIN: 'movementIndex',
PCST: 'podcast',
TCAT: 'category',
TDES: 'description',
TDRL: 'releasedate',
TGID: 'podcastId',
TKWD: 'keywords',
WFED: 'podcasturl',
GRP1: 'grouping'
};
export class ID3v24TagMapper extends CaseInsensitiveTagMap {
static toRating(popm) {
return {
source: popm.email,
rating: popm.rating > 0 ? (popm.rating - 1) / 254 * CommonTagMapper.maxRatingScore : undefined
};
}
constructor() {
super(['ID3v2.3', 'ID3v2.4'], id3v24TagMap);
}
/**
* Handle post mapping exceptions / correction
* @param tag to post map
* @param warnings Wil be used to register (collect) warnings
*/
postMap(tag, warnings) {
switch (tag.id) {
case 'UFID':
{
// decode MusicBrainz Recording Id
const idTag = tag.value;
if (idTag.owner_identifier === 'http://musicbrainz.org') {
tag.id += `:${idTag.owner_identifier}`;
tag.value = decodeString(idTag.identifier, 'latin1'); // latin1 == iso-8859-1
}
}
break;
case 'PRIV':
{
const customTag = tag.value;
switch (customTag.owner_identifier) {
// decode Windows Media Player
case 'AverageLevel':
case 'PeakValue':
tag.id += `:${customTag.owner_identifier}`;
tag.value = customTag.data.length === 4 ? UINT32_LE.get(customTag.data, 0) : null;
if (tag.value === null) {
warnings.addWarning('Failed to parse PRIV:PeakValue');
}
break;
default:
warnings.addWarning(`Unknown PRIV owner-identifier: ${customTag.data}`);
}
}
break;
case 'POPM':
tag.value = ID3v24TagMapper.toRating(tag.value);
break;
default:
break;
}
}
}
//# sourceMappingURL=ID3v24TagMapper.js.map