UNPKG

music-metadata

Version:

Music metadata parser for Node.js, supporting virtual any audio and tag format.

195 lines 6.9 kB
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