music-metadata 8.3.0 → 9.0.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 (91) hide show
  1. package/README.md +152 -132
  2. package/lib/ParserFactory.d.ts +1 -1
  3. package/lib/ParserFactory.js +1 -2
  4. package/lib/aiff/AiffParser.js +3 -4
  5. package/lib/aiff/AiffToken.d.ts +2 -4
  6. package/lib/aiff/AiffToken.js +7 -7
  7. package/lib/apev2/APEv2Parser.d.ts +1 -1
  8. package/lib/apev2/APEv2Parser.js +10 -12
  9. package/lib/apev2/APEv2Token.d.ts +1 -1
  10. package/lib/asf/AsfObject.d.ts +15 -17
  11. package/lib/asf/AsfObject.js +51 -45
  12. package/lib/asf/AsfParser.js +6 -8
  13. package/lib/asf/AsfUtil.d.ts +1 -3
  14. package/lib/asf/AsfUtil.js +4 -5
  15. package/lib/asf/GUID.d.ts +4 -5
  16. package/lib/asf/GUID.js +14 -11
  17. package/lib/common/BasicParser.d.ts +1 -1
  18. package/lib/common/FourCC.d.ts +1 -1
  19. package/lib/common/FourCC.js +5 -3
  20. package/lib/common/MetadataCollector.d.ts +3 -3
  21. package/lib/common/MetadataCollector.js +7 -8
  22. package/lib/common/RandomFileReader.d.ts +0 -1
  23. package/lib/common/Util.d.ts +1 -1
  24. package/lib/common/Util.js +4 -3
  25. package/lib/core.d.ts +16 -8
  26. package/lib/core.js +19 -5
  27. package/lib/dsdiff/DsdiffParser.js +1 -1
  28. package/lib/dsdiff/DsdiffToken.d.ts +1 -1
  29. package/lib/dsf/DsfChunk.d.ts +1 -1
  30. package/lib/flac/FlacParser.d.ts +1 -1
  31. package/lib/flac/FlacParser.js +6 -4
  32. package/lib/id3v1/ID3v1Parser.js +6 -6
  33. package/lib/id3v2/AbstractID3Parser.d.ts +1 -1
  34. package/lib/id3v2/AbstractID3Parser.js +1 -1
  35. package/lib/id3v2/FrameParser.js +3 -3
  36. package/lib/id3v2/ID3v24TagMapper.d.ts +2 -3
  37. package/lib/id3v2/ID3v24TagMapper.js +4 -4
  38. package/lib/id3v2/ID3v2Parser.d.ts +1 -1
  39. package/lib/id3v2/ID3v2Parser.js +10 -17
  40. package/lib/id3v2/ID3v2Token.d.ts +1 -1
  41. package/lib/id3v2/ID3v2Token.js +2 -2
  42. package/lib/iff/index.d.ts +1 -1
  43. package/lib/index.d.ts +1 -2
  44. package/lib/index.js +1 -1
  45. package/lib/lyrics3/Lyrics3.js +1 -1
  46. package/lib/matroska/MatroskaParser.d.ts +1 -1
  47. package/lib/matroska/MatroskaParser.js +16 -20
  48. package/lib/matroska/types.d.ts +0 -1
  49. package/lib/mp4/Atom.d.ts +1 -1
  50. package/lib/mp4/AtomToken.d.ts +2 -3
  51. package/lib/mp4/AtomToken.js +2 -2
  52. package/lib/mp4/MP4Parser.js +20 -19
  53. package/lib/mpeg/ExtendedLameHeader.d.ts +1 -1
  54. package/lib/mpeg/MpegParser.js +1 -1
  55. package/lib/mpeg/ReplayGainDataFormat.d.ts +1 -1
  56. package/lib/mpeg/XingTag.d.ts +1 -2
  57. package/lib/musepack/index.js +1 -1
  58. package/lib/musepack/sv7/BitReader.d.ts +1 -1
  59. package/lib/musepack/sv7/StreamVersion7.d.ts +1 -1
  60. package/lib/musepack/sv7/StreamVersion7.js +1 -1
  61. package/lib/musepack/sv8/StreamVersion8.d.ts +1 -1
  62. package/lib/musepack/sv8/StreamVersion8.js +1 -1
  63. package/lib/ogg/Ogg.d.ts +2 -2
  64. package/lib/ogg/OggParser.d.ts +1 -1
  65. package/lib/ogg/OggParser.js +5 -5
  66. package/lib/ogg/opus/Opus.d.ts +1 -1
  67. package/lib/ogg/opus/Opus.js +6 -6
  68. package/lib/ogg/opus/OpusParser.d.ts +2 -3
  69. package/lib/ogg/opus/OpusParser.js +2 -2
  70. package/lib/ogg/speex/Speex.d.ts +1 -1
  71. package/lib/ogg/speex/Speex.js +13 -13
  72. package/lib/ogg/speex/SpeexParser.d.ts +1 -2
  73. package/lib/ogg/theora/Theora.d.ts +1 -1
  74. package/lib/ogg/theora/Theora.js +6 -6
  75. package/lib/ogg/theora/TheoraParser.d.ts +4 -5
  76. package/lib/ogg/theora/TheoraParser.js +4 -4
  77. package/lib/ogg/vorbis/Vorbis.d.ts +3 -4
  78. package/lib/ogg/vorbis/Vorbis.js +11 -12
  79. package/lib/ogg/vorbis/VorbisDecoder.js +1 -1
  80. package/lib/ogg/vorbis/VorbisParser.d.ts +6 -7
  81. package/lib/ogg/vorbis/VorbisParser.js +11 -11
  82. package/lib/riff/RiffChunk.d.ts +1 -1
  83. package/lib/riff/RiffChunk.js +2 -2
  84. package/lib/type.d.ts +9 -11
  85. package/lib/wav/BwfChunk.d.ts +1 -1
  86. package/lib/wav/WaveChunk.d.ts +2 -3
  87. package/lib/wav/WaveChunk.js +8 -7
  88. package/lib/wav/WaveParser.js +2 -2
  89. package/lib/wavpack/WavPackParser.js +1 -1
  90. package/lib/wavpack/WavPackToken.d.ts +1 -1
  91. package/package.json +26 -25
@@ -1,3 +1,4 @@
1
+ import { StringType } from 'token-types';
1
2
  export function getBit(buf, off, bit) {
2
3
  return (buf[off] & (1 << bit)) !== 0;
3
4
  }
@@ -11,7 +12,7 @@ export function getBit(buf, off, bit) {
11
12
  */
12
13
  export function findZero(uint8Array, start, end, encoding) {
13
14
  let i = start;
14
- if (encoding === 'utf16le') {
15
+ if (encoding === 'utf-16le') {
15
16
  while (uint8Array[i] !== 0 || uint8Array[i + 1] !== 0) {
16
17
  if (i >= end)
17
18
  return end;
@@ -52,13 +53,13 @@ export function decodeString(uint8Array, encoding) {
52
53
  if (uint8Array[0] === 0xFF && uint8Array[1] === 0xFE) { // little endian
53
54
  return decodeString(uint8Array.subarray(2), encoding);
54
55
  }
55
- else if (encoding === 'utf16le' && uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) {
56
+ else if (encoding === 'utf-16le' && uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) {
56
57
  // BOM, indicating big endian decoding
57
58
  if ((uint8Array.length & 1) !== 0)
58
59
  throw new Error('Expected even number of octets for 16-bit unicode string');
59
60
  return decodeString(swapBytes(uint8Array), encoding);
60
61
  }
61
- return Buffer.from(uint8Array).toString(encoding);
62
+ return new StringType(uint8Array.length, encoding).get(uint8Array, 0);
62
63
  }
63
64
  export function stripNulls(str) {
64
65
  str = str.replace(/^\x00+/g, '');
package/lib/core.d.ts CHANGED
@@ -1,16 +1,24 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import { Readable } from 'stream';
3
- import * as strtok3 from 'strtok3/core';
4
- import { IAudioMetadata, INativeTagDict, IOptions, IPicture, IPrivateOptions, IRandomReader, ITag } from './type.js';
5
- export { IFileInfo } from 'strtok3/core';
1
+ import * as strtok3 from 'strtok3';
2
+ import type { IAudioMetadata, INativeTagDict, IOptions, IPicture, IPrivateOptions, IRandomReader, ITag } from './type.js';
3
+ import type { ReadableStream as NodeReadableStream } from 'node:stream/web';
4
+ export { IFileInfo } from 'strtok3';
5
+ export type AnyWebStream<G> = NodeReadableStream<G> | ReadableStream<G>;
6
6
  /**
7
- * Parse audio from Node Stream.Readable
8
- * @param stream - Stream to read the audio track from
7
+ * Parse Web API File
8
+ * Requires Blob to be able to stream using a ReadableStreamBYOBReader, only available since Node.js ≥ 20
9
+ * @param blob - Blob to parse
10
+ * @param options - Parsing options
11
+ * @returns Metadata
12
+ */
13
+ export declare function parseBlob(blob: Blob, options?: IOptions): Promise<IAudioMetadata>;
14
+ /**
15
+ * Parse audio from Web Stream.Readable
16
+ * @param webStream - WebStream to read the audio track from
9
17
  * @param options - Parsing options
10
18
  * @param fileInfo - File information object or MIME-type string
11
19
  * @returns Metadata
12
20
  */
13
- export declare function parseStream(stream: Readable, fileInfo?: strtok3.IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
21
+ export declare function parseWebStream(webStream: AnyWebStream<Uint8Array>, fileInfo?: strtok3.IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
14
22
  /**
15
23
  * Parse audio from Node Buffer
16
24
  * @param uint8Array - Uint8Array holding audio data
package/lib/core.js CHANGED
@@ -1,18 +1,32 @@
1
- import * as strtok3 from 'strtok3/core';
1
+ import * as strtok3 from 'strtok3';
2
2
  import { ParserFactory } from './ParserFactory.js';
3
3
  import { RandomUint8ArrayReader } from './common/RandomUint8ArrayReader.js';
4
4
  import { APEv2Parser } from './apev2/APEv2Parser.js';
5
5
  import { hasID3v1Header } from './id3v1/ID3v1Parser.js';
6
6
  import { getLyricsHeaderLength } from './lyrics3/Lyrics3.js';
7
7
  /**
8
- * Parse audio from Node Stream.Readable
9
- * @param stream - Stream to read the audio track from
8
+ * Parse Web API File
9
+ * Requires Blob to be able to stream using a ReadableStreamBYOBReader, only available since Node.js ≥ 20
10
+ * @param blob - Blob to parse
11
+ * @param options - Parsing options
12
+ * @returns Metadata
13
+ */
14
+ export async function parseBlob(blob, options = {}) {
15
+ const fileInfo = { mimeType: blob.type, size: blob.size };
16
+ if (blob instanceof File) {
17
+ fileInfo.path = blob.name;
18
+ }
19
+ return parseWebStream(blob.stream(), fileInfo, options);
20
+ }
21
+ /**
22
+ * Parse audio from Web Stream.Readable
23
+ * @param webStream - WebStream to read the audio track from
10
24
  * @param options - Parsing options
11
25
  * @param fileInfo - File information object or MIME-type string
12
26
  * @returns Metadata
13
27
  */
14
- export function parseStream(stream, fileInfo, options = {}) {
15
- return parseFromTokenizer(strtok3.fromStream(stream, typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo), options);
28
+ export function parseWebStream(webStream, fileInfo, options = {}) {
29
+ return parseFromTokenizer(strtok3.fromWebStream(webStream, typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo), options);
16
30
  }
17
31
  /**
18
32
  * Parse audio from Node Buffer
@@ -1,6 +1,6 @@
1
1
  import * as Token from 'token-types';
2
2
  import initDebug from 'debug';
3
- import * as strtok3 from 'strtok3/core';
3
+ import * as strtok3 from 'strtok3';
4
4
  import { FourCcToken } from '../common/FourCC.js';
5
5
  import { BasicParser } from '../common/BasicParser.js';
6
6
  import { ID3v2Parser } from '../id3v2/ID3v2Parser.js';
@@ -1,4 +1,4 @@
1
- import { IGetToken } from 'strtok3/core';
1
+ import type { IGetToken } from 'strtok3';
2
2
  import { IChunkHeader64 } from '../iff/index.js';
3
3
  export { IChunkHeader64 } from '../iff/index.js';
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { IGetToken } from 'strtok3/core';
1
+ import type { IGetToken } from 'strtok3';
2
2
  /**
3
3
  * Common interface for the common chunk DSD header
4
4
  */
@@ -1,4 +1,4 @@
1
- import { ITokenizer } from 'strtok3/core';
1
+ import type { ITokenizer } from 'strtok3';
2
2
  import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
3
3
  import { INativeMetadataCollector } from '../common/MetadataCollector.js';
4
4
  import { IOptions } from '../type.js';
@@ -54,7 +54,7 @@ export class FlacParser extends AbstractID3Parser {
54
54
  this.metadata.setFormat('bitrate', 8 * dataSize / this.metadata.format.duration);
55
55
  }
56
56
  }
57
- parseDataBlock(blockHeader) {
57
+ async parseDataBlock(blockHeader) {
58
58
  debug(`blockHeader type=${blockHeader.type}, length=${blockHeader.length}`);
59
59
  switch (blockHeader.type) {
60
60
  case BlockType.STREAMINFO:
@@ -71,7 +71,8 @@ export class FlacParser extends AbstractID3Parser {
71
71
  case BlockType.CUESHEET:
72
72
  break;
73
73
  case BlockType.PICTURE:
74
- return this.parsePicture(blockHeader.length).then();
74
+ await this.parsePicture(blockHeader.length);
75
+ return;
75
76
  default:
76
77
  this.metadata.addWarning('Unknown block type: ' + blockHeader.type);
77
78
  }
@@ -104,10 +105,11 @@ export class FlacParser extends AbstractID3Parser {
104
105
  const decoder = new VorbisDecoder(data, 0);
105
106
  decoder.readStringUtf8(); // vendor (skip)
106
107
  const commentListLength = decoder.readInt32();
108
+ const tags = new Array(commentListLength);
107
109
  for (let i = 0; i < commentListLength; i++) {
108
- const tag = decoder.parseUserComment();
109
- this.vorbisParser.addTag(tag.key, tag.value);
110
+ tags[i] = decoder.parseUserComment();
110
111
  }
112
+ await Promise.all(tags.map(tag => this.vorbisParser.addTag(tag.key, tag.value)));
111
113
  }
112
114
  async parsePicture(dataLen) {
113
115
  if (this.options.skipCovers) {
@@ -68,7 +68,7 @@ const Iid3v1Token = {
68
68
  };
69
69
  class Id3v1StringType extends StringType {
70
70
  constructor(len) {
71
- super(len, 'binary');
71
+ super(len, 'latin1');
72
72
  }
73
73
  get(buf, off) {
74
74
  let value = super.get(buf, off);
@@ -105,25 +105,25 @@ export class ID3v1Parser extends BasicParser {
105
105
  debug('ID3v1 header found at: pos=%s', this.tokenizer.fileInfo.size - Iid3v1Token.len);
106
106
  for (const id of ['title', 'artist', 'album', 'comment', 'track', 'year']) {
107
107
  if (header[id] && header[id] !== '')
108
- this.addTag(id, header[id]);
108
+ await this.addTag(id, header[id]);
109
109
  }
110
110
  const genre = ID3v1Parser.getGenre(header.genre);
111
111
  if (genre)
112
- this.addTag('genre', genre);
112
+ await this.addTag('genre', genre);
113
113
  }
114
114
  else {
115
115
  debug('ID3v1 header not found at: pos=%s', this.tokenizer.fileInfo.size - Iid3v1Token.len);
116
116
  }
117
117
  }
118
- addTag(id, value) {
119
- this.metadata.addTag('ID3v1', id, value);
118
+ async addTag(id, value) {
119
+ await this.metadata.addTag('ID3v1', id, value);
120
120
  }
121
121
  }
122
122
  export async function hasID3v1Header(reader) {
123
123
  if (reader.fileSize >= 128) {
124
124
  const tag = Buffer.alloc(3);
125
125
  await reader.randomRead(tag, 0, tag.length, reader.fileSize - 128);
126
- return tag.toString('binary') === 'TAG';
126
+ return tag.toString('latin1') === 'TAG';
127
127
  }
128
128
  return false;
129
129
  }
@@ -1,4 +1,4 @@
1
- import { ITokenizer } from 'strtok3/core';
1
+ import { ITokenizer } from 'strtok3';
2
2
  import { BasicParser } from '../common/BasicParser.js';
3
3
  /**
4
4
  * Abstract parser which tries take ID3v2 and ID3v1 headers.
@@ -1,4 +1,4 @@
1
- import { EndOfStreamError } from 'strtok3/core';
1
+ import { EndOfStreamError } from 'strtok3';
2
2
  import initDebug from 'debug';
3
3
  import { ID3v2Header } from './ID3v2Token.js';
4
4
  import { ID3v2Parser } from './ID3v2Parser.js';
@@ -159,7 +159,7 @@ export class FrameParser {
159
159
  fzero = util.findZero(uint8Array, offset, length, encoding);
160
160
  pic.description = util.decodeString(uint8Array.slice(offset, fzero), encoding);
161
161
  offset = fzero + nullTerminatorLength;
162
- pic.data = Buffer.from(uint8Array.slice(offset, length));
162
+ pic.data = uint8Array.slice(offset, length);
163
163
  output = pic;
164
164
  }
165
165
  break;
@@ -246,7 +246,7 @@ export class FrameParser {
246
246
  // Decode URL
247
247
  fzero = util.findZero(uint8Array, offset + 1, length, encoding);
248
248
  const description = util.decodeString(uint8Array.slice(offset + 1, fzero), encoding);
249
- offset = fzero + (encoding === 'utf16le' ? 2 : 1);
249
+ offset = fzero + (encoding === 'utf-16le' ? 2 : 1);
250
250
  output = { description, url: util.decodeString(uint8Array.slice(offset, length), defaultEnc) };
251
251
  break;
252
252
  }
@@ -320,6 +320,6 @@ export class FrameParser {
320
320
  return { id, data: uint8Array.slice(offset, length) };
321
321
  }
322
322
  static getNullTerminatorLength(enc) {
323
- return enc === 'utf16le' ? 2 : 1;
323
+ return enc === 'utf-16le' ? 2 : 1;
324
324
  }
325
325
  }
@@ -1,6 +1,6 @@
1
1
  import { CaseInsensitiveTagMap } from '../common/CaseInsensitiveTagMap.js';
2
- import { INativeMetadataCollector } from '../common/MetadataCollector.js';
3
- import { IRating, ITag } from '../type.js';
2
+ import type { INativeMetadataCollector } from '../common/MetadataCollector.js';
3
+ import type { IRating, ITag } from '../type.js';
4
4
  export declare class ID3v24TagMapper extends CaseInsensitiveTagMap {
5
5
  static toRating(popm: any): IRating;
6
6
  constructor();
@@ -8,7 +8,6 @@ export declare class ID3v24TagMapper extends CaseInsensitiveTagMap {
8
8
  * Handle post mapping exceptions / correction
9
9
  * @param tag to post map
10
10
  * @param warnings Wil be used to register (collect) warnings
11
- * @return Common value e.g. "Buena Vista Social Club"
12
11
  */
13
12
  protected postMap(tag: ITag, warnings: INativeMetadataCollector): void;
14
13
  }
@@ -1,6 +1,7 @@
1
+ import { UINT32_LE } from 'token-types';
1
2
  import { CommonTagMapper } from '../common/GenericTagMapper.js';
2
3
  import { CaseInsensitiveTagMap } from '../common/CaseInsensitiveTagMap.js';
3
- import * as util from '../common/Util.js';
4
+ import { decodeString } from '../common/Util.js';
4
5
  /**
5
6
  * ID3v2.3/ID3v2.4 tag mappings
6
7
  */
@@ -152,7 +153,6 @@ export class ID3v24TagMapper extends CaseInsensitiveTagMap {
152
153
  * Handle post mapping exceptions / correction
153
154
  * @param tag to post map
154
155
  * @param warnings Wil be used to register (collect) warnings
155
- * @return Common value e.g. "Buena Vista Social Club"
156
156
  */
157
157
  postMap(tag, warnings) {
158
158
  var _a, _b;
@@ -160,7 +160,7 @@ export class ID3v24TagMapper extends CaseInsensitiveTagMap {
160
160
  case 'UFID': // decode MusicBrainz Recording Id
161
161
  if (tag.value.owner_identifier === 'http://musicbrainz.org') {
162
162
  tag.id += ':' + tag.value.owner_identifier;
163
- tag.value = util.decodeString(tag.value.identifier, 'latin1'); // latin1 == iso-8859-1
163
+ tag.value = decodeString(tag.value.identifier, 'latin1'); // latin1 == iso-8859-1
164
164
  }
165
165
  break;
166
166
  case 'PRIV':
@@ -169,7 +169,7 @@ export class ID3v24TagMapper extends CaseInsensitiveTagMap {
169
169
  case 'AverageLevel':
170
170
  case 'PeakValue':
171
171
  tag.id += ':' + tag.value.owner_identifier;
172
- tag.value = tag.value.data.length === 4 ? tag.value.data.readUInt32LE(0) : null;
172
+ tag.value = tag.value.data.length === 4 ? UINT32_LE.get(tag.value.data, 0) : null;
173
173
  if (tag.value === null) {
174
174
  warnings.addWarning(`Failed to parse PRIV:PeakValue`);
175
175
  }
@@ -1,4 +1,4 @@
1
- import { ITokenizer } from 'strtok3/core';
1
+ import type { ITokenizer } from 'strtok3';
2
2
  import { IOptions } from '../type.js';
3
3
  import { INativeMetadataCollector } from '../common/MetadataCollector.js';
4
4
  export declare class ID3v2Parser {
@@ -2,6 +2,7 @@ import * as Token from 'token-types';
2
2
  import * as util from '../common/Util.js';
3
3
  import { FrameParser } from './FrameParser.js';
4
4
  import { ExtendedHeader, ID3v2Header, UINT32SYNCSAFE } from './ID3v2Token.js';
5
+ const asciiDecoder = new TextDecoder('ascii');
5
6
  export class ID3v2Parser {
6
7
  static removeUnsyncBytes(buffer) {
7
8
  let readI = 0;
@@ -98,33 +99,25 @@ export class ID3v2Parser {
98
99
  for (const tag of this.parseMetadata(uint8Array)) {
99
100
  if (tag.id === 'TXXX') {
100
101
  if (tag.value) {
101
- for (const text of tag.value.text) {
102
- this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, tag.value.description), text);
103
- }
102
+ await Promise.all(tag.value.text.map(text => this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, tag.value.description), text)));
104
103
  }
105
104
  }
106
105
  else if (tag.id === 'COM') {
107
- for (const value of tag.value) {
108
- this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, value.description), value.text);
109
- }
106
+ await Promise.all(tag.value.map(value => this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, value.description), value.text)));
110
107
  }
111
108
  else if (tag.id === 'COMM') {
112
- for (const value of tag.value) {
113
- this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, value.description), value);
114
- }
109
+ await Promise.all(tag.value.map(value => this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, value.description), value)));
115
110
  }
116
111
  else if (Array.isArray(tag.value)) {
117
- for (const value of tag.value) {
118
- this.addTag(tag.id, value);
119
- }
112
+ await Promise.all(tag.value.map(value => this.addTag(tag.id, value)));
120
113
  }
121
114
  else {
122
- this.addTag(tag.id, tag.value);
115
+ await this.addTag(tag.id, tag.value);
123
116
  }
124
117
  }
125
118
  }
126
- addTag(id, value) {
127
- this.metadata.addTag(this.headerType, id, value);
119
+ async addTag(id, value) {
120
+ await this.metadata.addTag(this.headerType, id, value);
128
121
  }
129
122
  parseMetadata(data) {
130
123
  let offset = 0;
@@ -152,7 +145,7 @@ export class ID3v2Parser {
152
145
  switch (majorVer) {
153
146
  case 2:
154
147
  header = {
155
- id: Buffer.from(uint8Array.slice(0, 3)).toString('ascii'),
148
+ id: asciiDecoder.decode(uint8Array.slice(0, 3)),
156
149
  length: Token.UINT24_BE.get(uint8Array, 3)
157
150
  };
158
151
  if (!header.id.match(/[A-Z0-9]{3}/g)) {
@@ -162,7 +155,7 @@ export class ID3v2Parser {
162
155
  case 3:
163
156
  case 4:
164
157
  header = {
165
- id: Buffer.from(uint8Array.slice(0, 4)).toString('ascii'),
158
+ id: asciiDecoder.decode(uint8Array.slice(0, 4)),
166
159
  length: (majorVer === 4 ? UINT32SYNCSAFE : Token.UINT32_BE).get(uint8Array, 4),
167
160
  flags: ID3v2Parser.readFrameFlags(uint8Array.slice(8, 10))
168
161
  };
@@ -1,4 +1,4 @@
1
- import { IGetToken } from 'strtok3/core';
1
+ import type { IGetToken } from 'strtok3';
2
2
  import * as util from '../common/Util.js';
3
3
  /**
4
4
  * The picture type according to the ID3v2 APIC frame
@@ -91,9 +91,9 @@ export const TextEncodingToken = {
91
91
  case 0x00:
92
92
  return { encoding: 'latin1' }; // binary
93
93
  case 0x01:
94
- return { encoding: 'utf16le', bom: true };
94
+ return { encoding: 'utf-16le', bom: true };
95
95
  case 0x02:
96
- return { encoding: 'utf16le', bom: false };
96
+ return { encoding: 'utf-16le', bom: false };
97
97
  case 0x03:
98
98
  return { encoding: 'utf8', bom: false };
99
99
  default:
@@ -1,4 +1,4 @@
1
- import { IGetToken } from 'strtok3/core';
1
+ import type { IGetToken } from 'strtok3';
2
2
  /**
3
3
  * "EA IFF 85" Standard for Interchange Format Files
4
4
  * Ref: http://www.martinreddy.net/gfx/2d/IFF.txt
package/lib/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import * as Stream from 'stream';
3
2
  import * as strtok3 from 'strtok3';
4
3
  import { IAudioMetadata, IOptions } from './type.js';
5
4
  export { IAudioMetadata, IOptions, ITag, INativeTagDict, ICommonTagsResult, IFormat, IPicture, IRatio, IChapter } from './type.js';
6
- export { parseFromTokenizer, parseBuffer, selectCover, orderTags, ratingToStars, IFileInfo } from './core.js';
5
+ export { parseFromTokenizer, parseBuffer, parseBlob, selectCover, orderTags, ratingToStars, IFileInfo } from './core.js';
7
6
  /**
8
7
  * Parse audio from Node Stream.Readable
9
8
  * @param stream - Stream to read the audio track from
package/lib/index.js CHANGED
@@ -3,7 +3,7 @@ import initDebug from 'debug';
3
3
  import { parseFromTokenizer, scanAppendingHeaders } from './core.js';
4
4
  import { ParserFactory } from './ParserFactory.js';
5
5
  import { RandomFileReader } from './common/RandomFileReader.js';
6
- export { parseFromTokenizer, parseBuffer, selectCover, orderTags, ratingToStars } from './core.js';
6
+ export { parseFromTokenizer, parseBuffer, parseBlob, selectCover, orderTags, ratingToStars } from './core.js';
7
7
  const debug = initDebug('music-metadata:parser');
8
8
  /**
9
9
  * Parse audio from Node Stream.Readable
@@ -3,7 +3,7 @@ export async function getLyricsHeaderLength(reader) {
3
3
  if (reader.fileSize >= 143) {
4
4
  const buf = Buffer.alloc(15);
5
5
  await reader.randomRead(buf, 0, buf.length, reader.fileSize - 143);
6
- const txt = buf.toString('binary');
6
+ const txt = buf.toString('latin1');
7
7
  const tag = txt.substr(6);
8
8
  if (tag === endTag2) {
9
9
  return parseInt(txt.substr(0, 6), 10) + 15;
@@ -1,4 +1,4 @@
1
- import { ITokenizer } from 'strtok3/core';
1
+ import type { ITokenizer } from 'strtok3';
2
2
  import { INativeMetadataCollector } from '../common/MetadataCollector.js';
3
3
  import { BasicParser } from '../common/BasicParser.js';
4
4
  import { IOptions } from '../type.js';
@@ -44,7 +44,7 @@ export class MatroskaParser extends BasicParser {
44
44
  const timecodeScale = info.timecodeScale ? info.timecodeScale : 1000000;
45
45
  if (typeof info.duration === 'number') {
46
46
  const duration = info.duration * timecodeScale / 1000000000;
47
- this.addTag('segment:title', info.title);
47
+ await this.addTag('segment:title', info.title);
48
48
  this.metadata.setFormat('duration', duration);
49
49
  }
50
50
  }
@@ -87,28 +87,24 @@ export class MatroskaParser extends BasicParser {
87
87
  this.metadata.setFormat('numberOfChannels', audioTrack.audio.channels);
88
88
  }
89
89
  if (matroska.segment.tags) {
90
- matroska.segment.tags.tag.forEach(tag => {
90
+ await Promise.all(matroska.segment.tags.tag.map(async (tag) => {
91
91
  const target = tag.target;
92
92
  const targetType = (target === null || target === void 0 ? void 0 : target.targetTypeValue) ? TargetType[target.targetTypeValue] : ((target === null || target === void 0 ? void 0 : target.targetType) ? target.targetType : 'track');
93
- tag.simpleTags.forEach(simpleTag => {
93
+ await Promise.all(tag.simpleTags.map(async (simpleTag) => {
94
94
  const value = simpleTag.string ? simpleTag.string : simpleTag.binary;
95
- this.addTag(`${targetType}:${simpleTag.name}`, value);
96
- });
97
- });
95
+ await this.addTag(`${targetType}:${simpleTag.name}`, value);
96
+ }));
97
+ }));
98
98
  }
99
99
  if (matroska.segment.attachments) {
100
- matroska.segment.attachments.attachedFiles
100
+ await Promise.all(matroska.segment.attachments.attachedFiles
101
101
  .filter(file => file.mimeType.startsWith('image/'))
102
- .map(file => {
103
- return {
104
- data: file.data,
105
- format: file.mimeType,
106
- description: file.description,
107
- name: file.name
108
- };
109
- }).forEach(picture => {
110
- this.addTag('picture', picture);
111
- });
102
+ .map(file => this.addTag('picture', {
103
+ data: file.data,
104
+ format: file.mimeType,
105
+ description: file.description,
106
+ name: file.name
107
+ })));
112
108
  }
113
109
  }
114
110
  }
@@ -220,14 +216,14 @@ export class MatroskaParser extends BasicParser {
220
216
  }
221
217
  async readString(e) {
222
218
  const rawString = await this.tokenizer.readToken(new StringType(e.len, 'utf-8'));
223
- return rawString.replace(/\00.*$/g, '');
219
+ return rawString.replace(/\x00.*$/g, '');
224
220
  }
225
221
  async readBuffer(e) {
226
222
  const buf = Buffer.alloc(e.len);
227
223
  await this.tokenizer.readBuffer(buf);
228
224
  return buf;
229
225
  }
230
- addTag(tagId, value) {
231
- this.metadata.addTag('matroska', tagId, value);
226
+ async addTag(tagId, value) {
227
+ await this.metadata.addTag('matroska', tagId, value);
232
228
  }
233
229
  }
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  export interface IHeader {
3
2
  id: number;
4
3
  len: number;
package/lib/mp4/Atom.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as AtomToken from './AtomToken.js';
2
- import { ITokenizer } from 'strtok3/core';
2
+ import type { ITokenizer } from 'strtok3';
3
3
  export type AtomDataHandler = (atom: Atom, remaining: number) => Promise<void>;
4
4
  export declare class Atom {
5
5
  readonly header: AtomToken.IAtomHeader;
@@ -1,5 +1,4 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import { IToken, IGetToken } from 'strtok3/core';
1
+ import type { IToken, IGetToken } from 'strtok3';
3
2
  interface IVersionAndFlags {
4
3
  /**
5
4
  * A 1-byte specification of the version
@@ -183,7 +182,7 @@ export interface IDataAtom {
183
182
  /**
184
183
  * An array of bytes containing the value of the metadata.
185
184
  */
186
- value: Buffer;
185
+ value: Uint8Array;
187
186
  }
188
187
  /**
189
188
  * Data Atom Structure
@@ -10,7 +10,7 @@ export const Header = {
10
10
  throw new Error('Invalid atom header length');
11
11
  return {
12
12
  length: BigInt(length),
13
- name: new Token.StringType(4, 'binary').get(buf, off + 4)
13
+ name: new Token.StringType(4, 'latin1').get(buf, off + 4)
14
14
  };
15
15
  },
16
16
  put: (buf, off, hdr) => {
@@ -150,7 +150,7 @@ export class DataAtom {
150
150
  type: Token.UINT24_BE.get(buf, off + 1)
151
151
  },
152
152
  locale: Token.UINT24_BE.get(buf, off + 4),
153
- value: Buffer.from(new Token.Uint8ArrayType(this.len - 8).get(buf, off + 8))
153
+ value: new Token.Uint8ArrayType(this.len - 8).get(buf, off + 8)
154
154
  };
155
155
  }
156
156
  }