music-metadata 10.0.0 → 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +4 -3
  2. package/lib/ParserFactory.d.ts +20 -28
  3. package/lib/ParserFactory.js +204 -207
  4. package/lib/aiff/AiffParser.js +20 -18
  5. package/lib/aiff/AiffToken.d.ts +14 -2
  6. package/lib/aiff/AiffToken.js +12 -0
  7. package/lib/apev2/APEv2Parser.d.ts +4 -4
  8. package/lib/apev2/APEv2Parser.js +20 -12
  9. package/lib/apev2/APEv2Token.d.ts +2 -4
  10. package/lib/apev2/APEv2Token.js +1 -4
  11. package/lib/asf/AsfObject.d.ts +7 -16
  12. package/lib/asf/AsfObject.js +8 -34
  13. package/lib/asf/AsfParser.js +17 -10
  14. package/lib/asf/AsfTagMapper.d.ts +1 -1
  15. package/lib/asf/AsfTagMapper.js +3 -2
  16. package/lib/asf/AsfUtil.d.ts +3 -11
  17. package/lib/asf/AsfUtil.js +29 -30
  18. package/lib/asf/GUID.js +6 -9
  19. package/lib/common/BasicParser.d.ts +4 -4
  20. package/lib/common/BasicParser.js +6 -0
  21. package/lib/common/CaseInsensitiveTagMap.d.ts +1 -1
  22. package/lib/common/CombinedTagMapper.d.ts +5 -5
  23. package/lib/common/CombinedTagMapper.js +1 -1
  24. package/lib/common/FourCC.d.ts +1 -1
  25. package/lib/common/GenericTagMapper.d.ts +8 -8
  26. package/lib/common/GenericTagMapper.js +4 -4
  27. package/lib/common/GenericTagTypes.d.ts +5 -4
  28. package/lib/common/GenericTagTypes.js +2 -2
  29. package/lib/common/MetadataCollector.d.ts +9 -9
  30. package/lib/common/MetadataCollector.js +24 -17
  31. package/lib/common/RandomFileReader.d.ts +1 -1
  32. package/lib/common/RandomFileReader.js +1 -1
  33. package/lib/common/RandomUint8ArrayReader.d.ts +1 -1
  34. package/lib/common/Util.d.ts +2 -6
  35. package/lib/common/Util.js +9 -11
  36. package/lib/core.d.ts +7 -9
  37. package/lib/core.js +10 -7
  38. package/lib/dsdiff/DsdiffParser.js +26 -14
  39. package/lib/dsdiff/DsdiffToken.d.ts +2 -2
  40. package/lib/dsdiff/DsdiffToken.js +1 -0
  41. package/lib/dsf/DsfChunk.js +1 -0
  42. package/lib/dsf/DsfParser.js +4 -2
  43. package/lib/flac/FlacParser.d.ts +3 -3
  44. package/lib/flac/FlacParser.js +9 -12
  45. package/lib/id3v1/ID3v1Parser.d.ts +1 -1
  46. package/lib/id3v1/ID3v1Parser.js +7 -4
  47. package/lib/id3v2/AbstractID3Parser.d.ts +1 -1
  48. package/lib/id3v2/AbstractID3Parser.js +2 -1
  49. package/lib/id3v2/FrameParser.d.ts +28 -3
  50. package/lib/id3v2/FrameParser.js +50 -28
  51. package/lib/id3v2/ID3v22TagMapper.d.ts +1 -1
  52. package/lib/id3v2/ID3v24TagMapper.d.ts +2 -1
  53. package/lib/id3v2/ID3v24TagMapper.js +23 -16
  54. package/lib/id3v2/ID3v2Parser.d.ts +2 -2
  55. package/lib/id3v2/ID3v2Parser.js +19 -8
  56. package/lib/iff/index.js +1 -0
  57. package/lib/index.d.ts +5 -6
  58. package/lib/index.js +7 -8
  59. package/lib/lyrics3/Lyrics3.d.ts +1 -1
  60. package/lib/lyrics3/Lyrics3.js +1 -1
  61. package/lib/matroska/MatroskaDtd.d.ts +1 -1
  62. package/lib/matroska/MatroskaDtd.js +139 -138
  63. package/lib/matroska/MatroskaParser.d.ts +4 -4
  64. package/lib/matroska/MatroskaParser.js +12 -12
  65. package/lib/matroska/types.d.ts +6 -4
  66. package/lib/mp4/Atom.d.ts +3 -3
  67. package/lib/mp4/Atom.js +4 -7
  68. package/lib/mp4/AtomToken.js +2 -1
  69. package/lib/mp4/MP4Parser.js +29 -20
  70. package/lib/mp4/MP4TagMapper.d.ts +2 -2
  71. package/lib/mp4/MP4TagMapper.js +1 -1
  72. package/lib/mpeg/ExtendedLameHeader.d.ts +4 -4
  73. package/lib/mpeg/ExtendedLameHeader.js +2 -1
  74. package/lib/mpeg/MpegParser.d.ts +1 -1
  75. package/lib/mpeg/MpegParser.js +145 -96
  76. package/lib/mpeg/ReplayGainDataFormat.d.ts +1 -1
  77. package/lib/mpeg/ReplayGainDataFormat.js +1 -0
  78. package/lib/mpeg/XingTag.d.ts +4 -4
  79. package/lib/mpeg/XingTag.js +5 -4
  80. package/lib/musepack/index.js +1 -0
  81. package/lib/musepack/sv7/BitReader.js +14 -17
  82. package/lib/musepack/sv7/MpcSv7Parser.js +6 -1
  83. package/lib/musepack/sv7/StreamVersion7.js +1 -0
  84. package/lib/musepack/sv8/MpcSv8Parser.js +6 -2
  85. package/lib/musepack/sv8/StreamVersion8.d.ts +1 -1
  86. package/lib/musepack/sv8/StreamVersion8.js +1 -0
  87. package/lib/ogg/Ogg.d.ts +1 -1
  88. package/lib/ogg/Ogg.js +1 -0
  89. package/lib/ogg/OggParser.d.ts +3 -3
  90. package/lib/ogg/OggParser.js +25 -16
  91. package/lib/ogg/opus/Opus.d.ts +1 -1
  92. package/lib/ogg/opus/Opus.js +1 -0
  93. package/lib/ogg/opus/OpusParser.d.ts +4 -4
  94. package/lib/ogg/opus/OpusParser.js +2 -0
  95. package/lib/ogg/speex/Speex.js +1 -0
  96. package/lib/ogg/speex/SpeexParser.d.ts +4 -4
  97. package/lib/ogg/speex/SpeexParser.js +1 -0
  98. package/lib/ogg/theora/Theora.js +1 -0
  99. package/lib/ogg/theora/TheoraParser.d.ts +4 -4
  100. package/lib/ogg/theora/TheoraParser.js +1 -0
  101. package/lib/ogg/vorbis/Vorbis.d.ts +3 -3
  102. package/lib/ogg/vorbis/Vorbis.js +22 -11
  103. package/lib/ogg/vorbis/VorbisDecoder.d.ts +1 -1
  104. package/lib/ogg/vorbis/VorbisDecoder.js +1 -0
  105. package/lib/ogg/vorbis/VorbisParser.d.ts +4 -4
  106. package/lib/ogg/vorbis/VorbisParser.js +3 -2
  107. package/lib/ogg/vorbis/VorbisTagMapper.d.ts +2 -2
  108. package/lib/ogg/vorbis/VorbisTagMapper.js +2 -2
  109. package/lib/riff/RiffChunk.d.ts +3 -3
  110. package/lib/riff/RiffChunk.js +1 -0
  111. package/lib/riff/RiffInfoTagMap.d.ts +1 -1
  112. package/lib/type.d.ts +35 -25
  113. package/lib/wav/BwfChunk.js +1 -0
  114. package/lib/wav/WaveChunk.d.ts +1 -1
  115. package/lib/wav/WaveChunk.js +1 -0
  116. package/lib/wav/WaveParser.js +27 -17
  117. package/lib/wavpack/WavPackParser.d.ts +1 -1
  118. package/lib/wavpack/WavPackParser.js +22 -13
  119. package/lib/wavpack/WavPackToken.d.ts +13 -17
  120. package/lib/wavpack/WavPackToken.js +22 -23
  121. package/package.json +15 -28
@@ -24,7 +24,7 @@ export class DsdiffParser extends BasicParser {
24
24
  this.metadata.setFormat('lossless', true);
25
25
  return this.readFmt8Chunks(header.chunkSize - BigInt(FourCcToken.len));
26
26
  default:
27
- throw Error(`Unsupported DSDIFF type: ${type}`);
27
+ throw new Error(`Unsupported DSDIFF type: ${type}`);
28
28
  }
29
29
  }
30
30
  async readFmt8Chunks(remainingSize) {
@@ -40,28 +40,35 @@ export class DsdiffParser extends BasicParser {
40
40
  debug(`Reading data of chunk[ID=${header.chunkID}, size=${header.chunkSize}]`);
41
41
  const p0 = this.tokenizer.position;
42
42
  switch (header.chunkID.trim()) {
43
- case 'FVER': // 3.1 FORMAT VERSION CHUNK
43
+ case 'FVER': { // 3.1 FORMAT VERSION CHUNK
44
44
  const version = await this.tokenizer.readToken(Token.UINT32_LE);
45
45
  debug(`DSDIFF version=${version}`);
46
46
  break;
47
- case 'PROP': // 3.2 PROPERTY CHUNK
47
+ }
48
+ case 'PROP': { // 3.2 PROPERTY CHUNK
48
49
  const propType = await this.tokenizer.readToken(FourCcToken);
49
50
  if (propType !== 'SND ')
50
51
  throw new Error('Unexpected PROP-chunk ID');
51
52
  await this.handleSoundPropertyChunks(header.chunkSize - BigInt(FourCcToken.len));
52
53
  break;
53
- case 'ID3': // Unofficial ID3 tag support
54
+ }
55
+ case 'ID3': { // Unofficial ID3 tag support
54
56
  const id3_data = await this.tokenizer.readToken(new Token.Uint8ArrayType(Number(header.chunkSize)));
55
57
  const rst = strtok3.fromBuffer(id3_data);
56
58
  await new ID3v2Parser().parse(this.metadata, rst, this.options);
57
59
  break;
60
+ }
61
+ case 'DSD':
62
+ if (this.metadata.format.numberOfChannels) {
63
+ this.metadata.setFormat('numberOfSamples', Number(header.chunkSize * BigInt(8) / BigInt(this.metadata.format.numberOfChannels)));
64
+ }
65
+ if (this.metadata.format.numberOfSamples && this.metadata.format.sampleRate) {
66
+ this.metadata.setFormat('duration', this.metadata.format.numberOfSamples / this.metadata.format.sampleRate);
67
+ }
68
+ break;
58
69
  default:
59
70
  debug(`Ignore chunk[ID=${header.chunkID}, size=${header.chunkSize}]`);
60
71
  break;
61
- case 'DSD':
62
- this.metadata.setFormat('numberOfSamples', Number(header.chunkSize * BigInt(8) / BigInt(this.metadata.format.numberOfChannels)));
63
- this.metadata.setFormat('duration', this.metadata.format.numberOfSamples / this.metadata.format.sampleRate);
64
- break;
65
72
  }
66
73
  const remaining = header.chunkSize - BigInt(this.tokenizer.position - p0);
67
74
  if (remaining > 0) {
@@ -76,16 +83,18 @@ export class DsdiffParser extends BasicParser {
76
83
  debug(`Sound-property-chunk[ID=${sndPropHeader.chunkID}, size=${sndPropHeader.chunkSize}]`);
77
84
  const p0 = this.tokenizer.position;
78
85
  switch (sndPropHeader.chunkID.trim()) {
79
- case 'FS': // 3.2.1 Sample Rate Chunk
86
+ case 'FS': { // 3.2.1 Sample Rate Chunk
80
87
  const sampleRate = await this.tokenizer.readToken(Token.UINT32_BE);
81
88
  this.metadata.setFormat('sampleRate', sampleRate);
82
89
  break;
83
- case 'CHNL': // 3.2.2 Channels Chunk
90
+ }
91
+ case 'CHNL': { // 3.2.2 Channels Chunk
84
92
  const numChannels = await this.tokenizer.readToken(Token.UINT16_BE);
85
93
  this.metadata.setFormat('numberOfChannels', numChannels);
86
94
  await this.handleChannelChunks(sndPropHeader.chunkSize - BigInt(Token.UINT16_BE.len));
87
95
  break;
88
- case 'CMPR': // 3.2.3 Compression Type Chunk
96
+ }
97
+ case 'CMPR': { // 3.2.3 Compression Type Chunk
89
98
  const compressionIdCode = (await this.tokenizer.readToken(FourCcToken)).trim();
90
99
  const count = await this.tokenizer.readToken(Token.UINT8);
91
100
  const compressionName = await this.tokenizer.readToken(new Token.StringType(count, 'ascii'));
@@ -95,18 +104,20 @@ export class DsdiffParser extends BasicParser {
95
104
  }
96
105
  this.metadata.setFormat('codec', `${compressionIdCode} (${compressionName})`);
97
106
  break;
98
- case 'ABSS': // 3.2.4 Absolute Start Time Chunk
107
+ }
108
+ case 'ABSS': { // 3.2.4 Absolute Start Time Chunk
99
109
  const hours = await this.tokenizer.readToken(Token.UINT16_BE);
100
110
  const minutes = await this.tokenizer.readToken(Token.UINT8);
101
111
  const seconds = await this.tokenizer.readToken(Token.UINT8);
102
112
  const samples = await this.tokenizer.readToken(Token.UINT32_BE);
103
113
  debug(`ABSS ${hours}:${minutes}:${seconds}.${samples}`);
104
114
  break;
105
- case 'LSCO': // 3.2.5 Loudspeaker Configuration Chunk
115
+ }
116
+ case 'LSCO': { // 3.2.5 Loudspeaker Configuration Chunk
106
117
  const lsConfig = await this.tokenizer.readToken(Token.UINT16_BE);
107
118
  debug(`LSCO lsConfig=${lsConfig}`);
108
119
  break;
109
- case 'COMT':
120
+ }
110
121
  default:
111
122
  debug(`Unknown sound-property-chunk[ID=${sndPropHeader.chunkID}, size=${sndPropHeader.chunkSize}]`);
112
123
  await this.tokenizer.ignore(Number(sndPropHeader.chunkSize));
@@ -137,3 +148,4 @@ export class DsdiffParser extends BasicParser {
137
148
  return channels;
138
149
  }
139
150
  }
151
+ //# sourceMappingURL=DsdiffParser.js.map
@@ -1,6 +1,6 @@
1
1
  import type { IGetToken } from 'strtok3';
2
- import { IChunkHeader64 } from '../iff/index.js';
3
- export { IChunkHeader64 } from '../iff/index.js';
2
+ import type { IChunkHeader64 } from '../iff/index.js';
3
+ export { type IChunkHeader64 } from '../iff/index.js';
4
4
  /**
5
5
  * DSDIFF chunk header
6
6
  * The data-size encoding is deviating from EA-IFF 85
@@ -16,3 +16,4 @@ export const ChunkHeader64 = {
16
16
  };
17
17
  }
18
18
  };
19
+ //# sourceMappingURL=DsdiffToken.js.map
@@ -49,3 +49,4 @@ export const FormatChunk = {
49
49
  };
50
50
  }
51
51
  };
52
+ //# sourceMappingURL=DsfChunk.js.map
@@ -17,7 +17,7 @@ export class DsfParser extends AbstractID3Parser {
17
17
  this.metadata.setFormat('lossless', true);
18
18
  const dsdChunk = await this.tokenizer.readToken(DsdChunk);
19
19
  if (dsdChunk.metadataPointer === BigInt(0)) {
20
- debug(`No ID3v2 tag present`);
20
+ debug("No ID3v2 tag present");
21
21
  }
22
22
  else {
23
23
  debug(`expect ID3v2 at offset=${dsdChunk.metadataPointer}`);
@@ -32,7 +32,7 @@ export class DsfParser extends AbstractID3Parser {
32
32
  const chunkHeader = await this.tokenizer.readToken(ChunkHeader);
33
33
  debug(`Parsing chunk name=${chunkHeader.id} size=${chunkHeader.size}`);
34
34
  switch (chunkHeader.id) {
35
- case 'fmt ':
35
+ case 'fmt ': {
36
36
  const formatChunk = await this.tokenizer.readToken(FormatChunk);
37
37
  this.metadata.setFormat('numberOfChannels', formatChunk.channelNum);
38
38
  this.metadata.setFormat('sampleRate', formatChunk.samplingFrequency);
@@ -42,6 +42,7 @@ export class DsfParser extends AbstractID3Parser {
42
42
  const bitrate = formatChunk.bitsPerSample * formatChunk.samplingFrequency * formatChunk.channelNum;
43
43
  this.metadata.setFormat('bitrate', bitrate);
44
44
  return; // We got what we want, stop further processing of chunks
45
+ }
45
46
  default:
46
47
  this.tokenizer.ignore(Number(chunkHeader.size) - ChunkHeader.len);
47
48
  break;
@@ -50,3 +51,4 @@ export class DsfParser extends AbstractID3Parser {
50
51
  }
51
52
  }
52
53
  }
54
+ //# sourceMappingURL=DsfParser.js.map
@@ -1,8 +1,8 @@
1
1
  import type { ITokenizer } from 'strtok3';
2
2
  import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
3
- import { INativeMetadataCollector } from '../common/MetadataCollector.js';
4
- import { IOptions } from '../type.js';
5
- import { ITokenParser } from '../ParserFactory.js';
3
+ import type { INativeMetadataCollector } from '../common/MetadataCollector.js';
4
+ import type { IOptions } from '../type.js';
5
+ import type { ITokenParser } from '../ParserFactory.js';
6
6
  export declare class FlacParser extends AbstractID3Parser {
7
7
  private vorbisParser;
8
8
  private padding;
@@ -45,7 +45,7 @@ export class FlacParser extends AbstractID3Parser {
45
45
  let blockHeader;
46
46
  do {
47
47
  // Read block header
48
- blockHeader = await this.tokenizer.readToken(Metadata.BlockHeader);
48
+ blockHeader = await this.tokenizer.readToken(BlockHeader);
49
49
  // Parse block data
50
50
  await this.parseDataBlock(blockHeader);
51
51
  } while (!blockHeader.lastBlock);
@@ -74,7 +74,7 @@ export class FlacParser extends AbstractID3Parser {
74
74
  await this.parsePicture(blockHeader.length);
75
75
  return;
76
76
  default:
77
- this.metadata.addWarning('Unknown block type: ' + blockHeader.type);
77
+ this.metadata.addWarning(`Unknown block type: ${blockHeader.type}`);
78
78
  }
79
79
  // Ignore data block
80
80
  return this.tokenizer.ignore(blockHeader.length).then();
@@ -83,9 +83,9 @@ export class FlacParser extends AbstractID3Parser {
83
83
  * Parse STREAMINFO
84
84
  */
85
85
  async parseBlockStreamInfo(dataLen) {
86
- if (dataLen !== Metadata.BlockStreamInfo.len)
86
+ if (dataLen !== BlockStreamInfo.len)
87
87
  throw new Error('Unexpected block-stream-info length');
88
- const streamInfo = await this.tokenizer.readToken(Metadata.BlockStreamInfo);
88
+ const streamInfo = await this.tokenizer.readToken(BlockStreamInfo);
89
89
  this.metadata.setFormat('container', 'FLAC');
90
90
  this.metadata.setFormat('codec', 'FLAC');
91
91
  this.metadata.setFormat('lossless', true);
@@ -115,15 +115,11 @@ export class FlacParser extends AbstractID3Parser {
115
115
  if (this.options.skipCovers) {
116
116
  return this.tokenizer.ignore(dataLen);
117
117
  }
118
- else {
119
- const picture = await this.tokenizer.readToken(new VorbisPictureToken(dataLen));
120
- this.vorbisParser.addTag('METADATA_BLOCK_PICTURE', picture);
121
- }
118
+ const picture = await this.tokenizer.readToken(new VorbisPictureToken(dataLen));
119
+ this.vorbisParser.addTag('METADATA_BLOCK_PICTURE', picture);
122
120
  }
123
121
  }
124
- class Metadata {
125
- }
126
- Metadata.BlockHeader = {
122
+ const BlockHeader = {
127
123
  len: 4,
128
124
  get: (buf, off) => {
129
125
  return {
@@ -137,7 +133,7 @@ Metadata.BlockHeader = {
137
133
  * METADATA_BLOCK_DATA
138
134
  * Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo
139
135
  */
140
- Metadata.BlockStreamInfo = {
136
+ const BlockStreamInfo = {
141
137
  len: 34,
142
138
  get: (buf, off) => {
143
139
  return {
@@ -171,3 +167,4 @@ Metadata.BlockStreamInfo = {
171
167
  };
172
168
  }
173
169
  };
170
+ //# sourceMappingURL=FlacParser.js.map
@@ -1,5 +1,5 @@
1
1
  import { BasicParser } from '../common/BasicParser.js';
2
- import { IRandomReader } from '../type.js';
2
+ import type { IRandomReader } from '../type.js';
3
3
  /**
4
4
  * ID3v1 Genre mappings
5
5
  * Ref: https://de.wikipedia.org/wiki/Liste_der_ID3v1-Genres
@@ -66,12 +66,13 @@ const Iid3v1Token = {
66
66
  } : null;
67
67
  }
68
68
  };
69
- class Id3v1StringType extends StringType {
69
+ class Id3v1StringType {
70
70
  constructor(len) {
71
- super(len, 'latin1');
71
+ this.len = len;
72
+ this.stringType = new StringType(len, 'latin1');
72
73
  }
73
74
  get(buf, off) {
74
- let value = super.get(buf, off);
75
+ let value = this.stringType.get(buf, off);
75
76
  value = util.trimRightNull(value);
76
77
  value = value.trim();
77
78
  return value.length > 0 ? value : undefined;
@@ -103,7 +104,8 @@ export class ID3v1Parser extends BasicParser {
103
104
  const header = await this.tokenizer.readToken(Iid3v1Token, offset);
104
105
  if (header) {
105
106
  debug('ID3v1 header found at: pos=%s', this.tokenizer.fileInfo.size - Iid3v1Token.len);
106
- for (const id of ['title', 'artist', 'album', 'comment', 'track', 'year']) {
107
+ const props = ['title', 'artist', 'album', 'comment', 'track', 'year'];
108
+ for (const id of props) {
107
109
  if (header[id] && header[id] !== '')
108
110
  await this.addTag(id, header[id]);
109
111
  }
@@ -127,3 +129,4 @@ export async function hasID3v1Header(reader) {
127
129
  }
128
130
  return false;
129
131
  }
132
+ //# sourceMappingURL=ID3v1Parser.js.map
@@ -1,4 +1,4 @@
1
- import { ITokenizer } from 'strtok3';
1
+ import { type ITokenizer } from 'strtok3';
2
2
  import { BasicParser } from '../common/BasicParser.js';
3
3
  /**
4
4
  * Abstract parser which tries take ID3v2 and ID3v1 headers.
@@ -22,7 +22,7 @@ export class AbstractID3Parser extends BasicParser {
22
22
  }
23
23
  catch (err) {
24
24
  if (err instanceof EndOfStreamError) {
25
- debug(`End-of-stream`);
25
+ debug("End-of-stream");
26
26
  }
27
27
  else {
28
28
  throw err;
@@ -54,3 +54,4 @@ export class AbstractID3Parser extends BasicParser {
54
54
  }
55
55
  }
56
56
  }
57
+ //# sourceMappingURL=AbstractID3Parser.js.map
@@ -1,5 +1,29 @@
1
- import { ID3v2MajorVersion, ITextEncoding } from './ID3v2Token.js';
2
- import { IWarningCollector } from '../common/MetadataCollector.js';
1
+ import { type ID3v2MajorVersion, type ITextEncoding } from './ID3v2Token.js';
2
+ import type { IWarningCollector } from '../common/MetadataCollector.js';
3
+ interface ICustomTag {
4
+ owner_identifier: string;
5
+ }
6
+ export interface ICustomDataTag extends ICustomTag {
7
+ data: Uint8Array;
8
+ }
9
+ export interface IIdentifierTag extends ICustomTag {
10
+ identifier: Uint8Array;
11
+ }
12
+ export interface ITextTag {
13
+ description: string;
14
+ text: string[];
15
+ }
16
+ export interface IPopularimeter {
17
+ email: string;
18
+ rating: number;
19
+ counter: number;
20
+ }
21
+ export interface IGeneralEncapsulatedObject {
22
+ type: string;
23
+ filename: string;
24
+ description: string;
25
+ data: Uint8Array;
26
+ }
3
27
  export declare function parseGenre(origVal: string): string[];
4
28
  export declare class FrameParser {
5
29
  private major;
@@ -10,7 +34,7 @@ export declare class FrameParser {
10
34
  * @param warningCollector - Used to collect decode issue
11
35
  */
12
36
  constructor(major: ID3v2MajorVersion, warningCollector: IWarningCollector);
13
- readData(uint8Array: Uint8Array, type: string, includeCovers: boolean): any;
37
+ readData(uint8Array: Uint8Array, type: string, includeCovers: boolean): unknown;
14
38
  protected static readNullTerminatedString(uint8Array: Uint8Array, encoding: ITextEncoding): {
15
39
  text: string;
16
40
  len: number;
@@ -33,3 +57,4 @@ export declare class FrameParser {
33
57
  private static readIdentifierAndData;
34
58
  private static getNullTerminatorLength;
35
59
  }
60
+ export {};
@@ -1,7 +1,7 @@
1
1
  import initDebug from 'debug';
2
2
  import * as Token from 'token-types';
3
3
  import * as util from '../common/Util.js';
4
- import { AttachedPictureType, TextEncodingToken, SyncTextHeader, TextHeader } from './ID3v2Token.js';
4
+ import { AttachedPictureType, SyncTextHeader, TextEncodingToken, TextHeader } from './ID3v2Token.js';
5
5
  import { Genres } from '../id3v1/ID3v1Parser.js';
6
6
  const debug = initDebug('music-metadata:id3v2:frame-parser');
7
7
  const defaultEnc = 'latin1'; // latin1 == iso-8859-1;
@@ -39,9 +39,11 @@ export function parseGenre(origVal) {
39
39
  }
40
40
  if (word) {
41
41
  if (genres.length === 0 && word.match(/^\d*$/)) {
42
- word = Genres[word];
42
+ word = parseGenreCode(word);
43
+ }
44
+ if (word) {
45
+ genres.push(word);
43
46
  }
44
- genres.push(word);
45
47
  }
46
48
  return genres;
47
49
  }
@@ -51,7 +53,7 @@ function parseGenreCode(code) {
51
53
  if (code === 'CR')
52
54
  return 'Cover';
53
55
  if (code.match(/^\d*$/)) {
54
- return Genres[code];
56
+ return Genres[Number.parseInt(code)];
55
57
  }
56
58
  }
57
59
  export class FrameParser {
@@ -83,20 +85,23 @@ export class FrameParser {
83
85
  case 'MVIN':
84
86
  case 'MVNM':
85
87
  case 'PCS':
86
- case 'PCST':
88
+ case 'PCST': {
87
89
  let text;
88
90
  try {
89
91
  text = util.decodeString(uint8Array.slice(1), encoding).replace(/\x00+$/, '');
90
92
  }
91
93
  catch (error) {
92
- this.warningCollector.addWarning(`id3v2.${this.major} type=${type} header has invalid string value: ${error.message}`);
94
+ if (error instanceof Error) {
95
+ this.warningCollector.addWarning(`id3v2.${this.major} type=${type} header has invalid string value: ${error.message}`);
96
+ break;
97
+ }
98
+ throw error;
93
99
  }
94
100
  switch (type) {
95
101
  case 'TMCL': // Musician credits list
96
102
  case 'TIPL': // Involved people list
97
103
  case 'IPLS': // Involved people list
98
- output = this.splitValue(type, text);
99
- output = FrameParser.functionList(output);
104
+ output = FrameParser.functionList(this.splitValue(type, text));
100
105
  break;
101
106
  case 'TRK':
102
107
  case 'TRCK':
@@ -126,13 +131,16 @@ export class FrameParser {
126
131
  output = this.major >= 4 ? this.splitValue(type, text) : [text];
127
132
  }
128
133
  break;
129
- case 'TXXX':
130
- output = FrameParser.readIdentifierAndData(uint8Array, offset + 1, length, encoding);
131
- output = {
132
- description: output.id,
133
- text: this.splitValue(type, util.decodeString(output.data, encoding).replace(/\x00+$/, ''))
134
+ }
135
+ case 'TXXX': {
136
+ const idAndData = FrameParser.readIdentifierAndData(uint8Array, offset + 1, length, encoding);
137
+ const textTag = {
138
+ description: idAndData.id,
139
+ text: this.splitValue(type, util.decodeString(idAndData.data, encoding).replace(/\x00+$/, ''))
134
140
  };
141
+ output = textTag;
135
142
  break;
143
+ }
136
144
  case 'PIC':
137
145
  case 'APIC':
138
146
  if (includeCovers) {
@@ -150,7 +158,7 @@ export class FrameParser {
150
158
  offset = fzero + 1;
151
159
  break;
152
160
  default:
153
- throw new Error('Warning: unexpected major versionIndex: ' + this.major);
161
+ throw new Error(`Warning: unexpected major versionIndex: ${this.major}`);
154
162
  }
155
163
  pic.format = FrameParser.fixPictureMimeType(pic.format);
156
164
  pic.type = AttachedPictureType[uint8Array[offset]];
@@ -166,7 +174,7 @@ export class FrameParser {
166
174
  case 'PCNT':
167
175
  output = Token.UINT32_BE.get(uint8Array, 0);
168
176
  break;
169
- case 'SYLT':
177
+ case 'SYLT': {
170
178
  const syltHeader = SyncTextHeader.get(uint8Array, 0);
171
179
  offset += SyncTextHeader.len;
172
180
  const result = {
@@ -195,10 +203,11 @@ export class FrameParser {
195
203
  }
196
204
  output = result;
197
205
  break;
206
+ }
198
207
  case 'ULT':
199
208
  case 'USLT':
200
209
  case 'COM':
201
- case 'COMM':
210
+ case 'COMM': {
202
211
  const textHeader = TextHeader.get(uint8Array, offset);
203
212
  offset += TextHeader.len;
204
213
  const descriptorStr = FrameParser.readNullTerminatedString(uint8Array.subarray(offset), textHeader.encoding);
@@ -211,15 +220,18 @@ export class FrameParser {
211
220
  };
212
221
  output = comment;
213
222
  break;
214
- case 'UFID':
215
- output = FrameParser.readIdentifierAndData(uint8Array, offset, length, defaultEnc);
216
- output = { owner_identifier: output.id, identifier: output.data };
223
+ }
224
+ case 'UFID': {
225
+ const ufid = FrameParser.readIdentifierAndData(uint8Array, offset, length, defaultEnc);
226
+ output = { owner_identifier: ufid.id, identifier: ufid.data };
217
227
  break;
218
- case 'PRIV': // private frame
219
- output = FrameParser.readIdentifierAndData(uint8Array, offset, length, defaultEnc);
220
- output = { owner_identifier: output.id, data: output.data };
228
+ }
229
+ case 'PRIV': { // private frame
230
+ const priv = FrameParser.readIdentifierAndData(uint8Array, offset, length, defaultEnc);
231
+ output = { owner_identifier: priv.id, data: priv.data };
221
232
  break;
222
- case 'POPM': // Popularimeter
233
+ }
234
+ case 'POPM': { // Popularimeter
223
235
  fzero = util.findZero(uint8Array, offset, length, defaultEnc);
224
236
  const email = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc);
225
237
  offset = fzero + 1;
@@ -230,6 +242,7 @@ export class FrameParser {
230
242
  counter: dataLen >= 5 ? Token.UINT32_BE.get(uint8Array, offset + 1) : undefined
231
243
  };
232
244
  break;
245
+ }
233
246
  case 'GEOB': { // General encapsulated object
234
247
  fzero = util.findZero(uint8Array, offset + 1, length, encoding);
235
248
  const mimeType = util.decodeString(uint8Array.slice(offset + 1, fzero), defaultEnc);
@@ -239,12 +252,13 @@ export class FrameParser {
239
252
  offset = fzero + 1;
240
253
  fzero = util.findZero(uint8Array, offset, length - offset, encoding);
241
254
  const description = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc);
242
- output = {
255
+ const geob = {
243
256
  type: mimeType,
244
257
  filename,
245
258
  description,
246
259
  data: uint8Array.slice(offset + 1, length)
247
260
  };
261
+ output = geob;
248
262
  break;
249
263
  }
250
264
  // W-Frames:
@@ -257,6 +271,7 @@ export class FrameParser {
257
271
  case 'WPAY':
258
272
  case 'WPUB':
259
273
  // Decode URL
274
+ fzero = util.findZero(uint8Array, offset + 1, length, encoding);
260
275
  output = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc);
261
276
  break;
262
277
  case 'WXXX': {
@@ -277,15 +292,21 @@ export class FrameParser {
277
292
  break;
278
293
  }
279
294
  default:
280
- debug('Warning: unsupported id3v2-tag-type: ' + type);
295
+ debug(`Warning: unsupported id3v2-tag-type: ${type}`);
281
296
  break;
282
297
  }
283
298
  return output;
284
299
  }
285
300
  static readNullTerminatedString(uint8Array, encoding) {
286
301
  let offset = encoding.bom ? 2 : 0;
287
- const txt = uint8Array.slice(offset, offset = util.findZero(uint8Array, offset, uint8Array.length, encoding.encoding));
288
- offset += encoding.encoding === 'utf-16le' ? 2 : 1;
302
+ const zeroIndex = util.findZero(uint8Array, offset, uint8Array.length, encoding.encoding);
303
+ const txt = uint8Array.slice(offset, zeroIndex);
304
+ if (encoding.encoding === 'utf-16le') {
305
+ offset = zeroIndex + 2;
306
+ }
307
+ else {
308
+ offset = zeroIndex + 1;
309
+ }
289
310
  return {
290
311
  text: util.decodeString(txt, encoding.encoding),
291
312
  len: offset
@@ -309,7 +330,7 @@ export class FrameParser {
309
330
  const res = {};
310
331
  for (let i = 0; i + 1 < entries.length; i += 2) {
311
332
  const names = entries[i + 1].split(',');
312
- res[entries[i]] = res.hasOwnProperty(entries[i]) ? res[entries[i]].concat(names) : names;
333
+ res[entries[i]] = res[entries[i]] ? res[entries[i]].concat(names) : names;
313
334
  }
314
335
  return res;
315
336
  }
@@ -349,3 +370,4 @@ export class FrameParser {
349
370
  return enc === 'utf-16le' ? 2 : 1;
350
371
  }
351
372
  }
373
+ //# sourceMappingURL=FrameParser.js.map
@@ -1,4 +1,4 @@
1
- import { INativeTagMap } from '../common/GenericTagTypes.js';
1
+ import type { INativeTagMap } from '../common/GenericTagTypes.js';
2
2
  import { CaseInsensitiveTagMap } from '../common/CaseInsensitiveTagMap.js';
3
3
  /**
4
4
  * ID3v2.2 tag mappings
@@ -1,8 +1,9 @@
1
1
  import { CaseInsensitiveTagMap } from '../common/CaseInsensitiveTagMap.js';
2
2
  import type { INativeMetadataCollector } from '../common/MetadataCollector.js';
3
3
  import type { IRating, ITag } from '../type.js';
4
+ import type { IPopularimeter } from './FrameParser.js';
4
5
  export declare class ID3v24TagMapper extends CaseInsensitiveTagMap {
5
- static toRating(popm: any): IRating;
6
+ static toRating(popm: IPopularimeter): IRating;
6
7
  constructor();
7
8
  /**
8
9
  * Handle post mapping exceptions / correction
@@ -156,25 +156,32 @@ export class ID3v24TagMapper extends CaseInsensitiveTagMap {
156
156
  */
157
157
  postMap(tag, warnings) {
158
158
  switch (tag.id) {
159
- case 'UFID': // decode MusicBrainz Recording Id
160
- if (tag.value.owner_identifier === 'http://musicbrainz.org') {
161
- tag.id += ':' + tag.value.owner_identifier;
162
- tag.value = decodeString(tag.value.identifier, 'latin1'); // latin1 == iso-8859-1
159
+ case 'UFID':
160
+ {
161
+ // decode MusicBrainz Recording Id
162
+ const idTag = tag.value;
163
+ if (idTag.owner_identifier === 'http://musicbrainz.org') {
164
+ tag.id += `:${idTag.owner_identifier}`;
165
+ tag.value = decodeString(idTag.identifier, 'latin1'); // latin1 == iso-8859-1
166
+ }
163
167
  }
164
168
  break;
165
169
  case 'PRIV':
166
- switch (tag.value.owner_identifier) {
167
- // decode Windows Media Player
168
- case 'AverageLevel':
169
- case 'PeakValue':
170
- tag.id += ':' + tag.value.owner_identifier;
171
- tag.value = tag.value.data.length === 4 ? UINT32_LE.get(tag.value.data, 0) : null;
172
- if (tag.value === null) {
173
- warnings.addWarning(`Failed to parse PRIV:PeakValue`);
174
- }
175
- break;
176
- default:
177
- warnings.addWarning(`Unknown PRIV owner-identifier: ${tag.value.owner_identifier}`);
170
+ {
171
+ const customTag = tag.value;
172
+ switch (customTag.owner_identifier) {
173
+ // decode Windows Media Player
174
+ case 'AverageLevel':
175
+ case 'PeakValue':
176
+ tag.id += `:${customTag.owner_identifier}`;
177
+ tag.value = customTag.data.length === 4 ? UINT32_LE.get(customTag.data, 0) : null;
178
+ if (tag.value === null) {
179
+ warnings.addWarning('Failed to parse PRIV:PeakValue');
180
+ }
181
+ break;
182
+ default:
183
+ warnings.addWarning(`Unknown PRIV owner-identifier: ${customTag.data}`);
184
+ }
178
185
  }
179
186
  break;
180
187
  case 'POPM':
@@ -1,6 +1,6 @@
1
1
  import type { ITokenizer } from 'strtok3';
2
- import { IOptions } from '../type.js';
3
- import { INativeMetadataCollector } from '../common/MetadataCollector.js';
2
+ import type { IOptions } from '../type.js';
3
+ import type { INativeMetadataCollector } from '../common/MetadataCollector.js';
4
4
  export declare class ID3v2Parser {
5
5
  static removeUnsyncBytes(buffer: Uint8Array): Uint8Array;
6
6
  private static getFrameHeaderLength;