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
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ![Node.js CI](https://github.com/Borewit/music-metadata/workflows/Node.js%20CI/badge.svg)
1
+ [![Node.js CI](https://github.com/Borewit/music-metadata/actions/workflows/nodejs-ci.yml/badge.svg?branch=master)](https://github.com/Borewit/music-metadata/actions?query=branch%3Amaster)
2
2
  [![Build status](https://ci.appveyor.com/api/projects/status/tgtqynlon8t99qq5/branch/master?svg=true)](https://ci.appveyor.com/project/Borewit/music-metadata/branch/master)
3
3
  [![NPM version](https://img.shields.io/npm/v/music-metadata.svg)](https://npmjs.org/package/music-metadata)
4
4
  [![npm downloads](http://img.shields.io/npm/dm/music-metadata.svg)](https://npmcharts.com/compare/music-metadata,jsmediatags,musicmetadata,node-id3,mp3-parser,id3-parser,wav-file-info?start=600)
@@ -11,9 +11,15 @@
11
11
 
12
12
  # music-metadata
13
13
 
14
- Stream and file based music metadata parser for [node.js](https://nodejs.org/).
14
+ Stream and file based music metadata parser for [node.js](https://nodejs.org/) and browser projects.
15
15
  Supports any common audio and tagging format.
16
- [TypeScript](https://www.typescriptlang.org/) definitions are included.
16
+
17
+ ## Compatibility
18
+
19
+ Module: version 8 migrated from [CommonJS](https://en.wikipedia.org/wiki/CommonJS) to [pure ECMAScript Module (ESM)](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
20
+ JavaScript is compliant with [ECMAScript 2019 (ES10)](https://en.wikipedia.org/wiki/ECMAScript#10th_Edition_%E2%80%93_ECMAScript_2019).
21
+ Requires Node.js ≥ 16 engine.
22
+ Primarily designed for [Node.js](https://nodejs.org/), but has also been designed for browser compatibility.
17
23
 
18
24
  ## Features
19
25
 
@@ -25,12 +31,12 @@ Supports any common audio and tagging format.
25
31
  | AAC | ADTS / Advanced Audio Coding | [:link:](https://en.wikipedia.org/wiki/Advanced_Audio_Coding) | <img src="https://svgshare.com/i/UT8.svg" width="40" alt="AAC logo"> |
26
32
  | APE | Monkey's Audio | [:link:](https://wikipedia.org/wiki/Monkey's_Audio) | <img src="https://foreverhits.files.wordpress.com/2015/05/ape_audio.jpg" width="40" alt="Monkey's Audio logo"> |
27
33
  | ASF | Advanced Systems Format | [:link:](https://wikipedia.org/wiki/Advanced_Systems_Format) | |
28
- | BWF | Broadcast Wave Format | [:link:](https://en.wikipedia.org/wiki/Broadcast_Wave_Format) | |
34
+ | BWF | Broadcast Wave Format | [:link:](https://en.wikipedia.org/wiki/Broadcast_Wave_Format) | |
29
35
  | DSDIFF | Philips DSDIFF | [:link:](https://wikipedia.org/wiki/Direct_Stream_Digital) | <img src="https://upload.wikimedia.org/wikipedia/commons/b/bc/DSDlogo.svg" width="80" alt="DSD logo"> |
30
36
  | DSF | Sony's DSD Stream File | [:link:](https://wikipedia.org/wiki/Direct_Stream_Digital) | <img src="https://upload.wikimedia.org/wikipedia/commons/b/bc/DSDlogo.svg" width="80" alt="DSD logo"> |
31
37
  | FLAC | Free Lossless Audio Codec | [:link:](https://wikipedia.org/wiki/FLAC) | <img src="https://upload.wikimedia.org/wikipedia/commons/a/a2/FLAC_logo_vector.svg" width="80" alt="FLAC logo"> |
32
38
  | MP2 | MPEG-1 Audio Layer II | [:link:](https://wikipedia.org/wiki/MPEG-1_Audio_Layer_II) | |
33
- | Matroska | Matroska (EBML), mka, mkv | [:link:](https://wikipedia.org/wiki/Matroska) | <img src="https://upload.wikimedia.org/wikipedia/commons/1/1a/Matroska_2010.svg" width="80" alt="Matroska logo"> |
39
+ | Matroska | Matroska (EBML), mka, mkv | [:link:](https://wikipedia.org/wiki/Matroska) | <img src="https://upload.wikimedia.org/wikipedia/commons/1/1a/Matroska_2010.svg" width="80" alt="Matroska logo"> |
34
40
  | MP3 | MPEG-1 / MPEG-2 Audio Layer III | [:link:](https://wikipedia.org/wiki/MP3) | <img src="https://upload.wikimedia.org/wikipedia/commons/e/ea/Mp3.svg" width="80" alt="MP3 logo"> |
35
41
  | MPC | Musepack SV7 | [:link:](https://wikipedia.org/wiki/Musepack) | <img src="https://www.musepack.net/pictures/musepack_logo.png" width="80" alt="musepack logo"> |
36
42
  | MPEG 4 | mp4, m4a, m4v | [:link:](https://wikipedia.org/wiki/MPEG-4) | <img src="https://svgshare.com/i/UU3.svg" width="80" alt="mpeg 4 logo"> |
@@ -40,21 +46,21 @@ Supports any common audio and tagging format.
40
46
  | Theora | | [:link:](https://en.wikipedia.org/wiki/Theora) | <img src="https://upload.wikimedia.org/wikipedia/commons/5/57/Theora_logo_2007.svg" width="70" alt="Theora logo"> |
41
47
  | Vorbis | Vorbis audio compression | [:link:](https://wikipedia.org/wiki/Ogg_Vorbis) | <img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Xiph.Org_logo_square.svg" width="70" alt="Vorbis logo"> |
42
48
  | WAV | RIFF WAVE | [:link:](https://wikipedia.org/wiki/WAV) | |
43
- | WebM | webm | [:link:](https://wikipedia.org/wiki/WebM) | <img src="https://upload.wikimedia.org/wikipedia/commons/3/34/WebM_logo.svg" width="80" alt="Matroska logo"> |
49
+ | WebM | webm | [:link:](https://wikipedia.org/wiki/WebM) | <img src="https://upload.wikimedia.org/wikipedia/commons/3/34/WebM_logo.svg" width="80" alt="Matroska logo"> |
44
50
  | WV | WavPack | [:link:](https://wikipedia.org/wiki/WavPack) | <img src="http://www.wavpack.com/wavpacklogo.svg" width="60" alt="WavPack logo"> |
45
51
  | WMA | Windows Media Audio | [:link:](https://wikipedia.org/wiki/Windows_Media_Audio) | <img src="https://upload.wikimedia.org/wikipedia/commons/7/76/Windows_Media_Player_simplified_logo.svg" width="40" alt="Windows Media logo"> |
46
52
 
47
53
  ### Supported tag headers
48
54
 
49
55
  Following tag header formats are supported:
50
- * [APE](https://wikipedia.org/wiki/APE_tag)
51
- * [ASF](https://wikipedia.org/wiki/Advanced_Systems_Format)
52
- * EXIF 2.3
53
- * [ID3](https://wikipedia.org/wiki/ID3): ID3v1, ID3v1.1, ID3v2.2, [ID3v2.3](http://id3.org/id3v2.3.0) & [ID3v2.4](http://id3.org/id3v2.4.0-frames)
54
- * [iTunes](https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata)
55
- * [RIFF](https://wikipedia.org/wiki/Resource_Interchange_File_Format)/INFO
56
- * [Vorbis comment](https://wikipedia.org/wiki/Vorbis_comment)
57
- * [AIFF](https://wikipedia.org/wiki/Audio_Interchange_File_Format)
56
+ * [APE](https://wikipedia.org/wiki/APE_tag)
57
+ * [ASF](https://wikipedia.org/wiki/Advanced_Systems_Format)
58
+ * EXIF 2.3
59
+ * [ID3](https://wikipedia.org/wiki/ID3): ID3v1, ID3v1.1, ID3v2.2, [ID3v2.3](http://id3.org/id3v2.3.0) & [ID3v2.4](http://id3.org/id3v2.4.0-frames)
60
+ * [iTunes](https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata)
61
+ * [RIFF](https://wikipedia.org/wiki/Resource_Interchange_File_Format)/INFO
62
+ * [Vorbis comment](https://wikipedia.org/wiki/Vorbis_comment)
63
+ * [AIFF](https://wikipedia.org/wiki/Audio_Interchange_File_Format)
58
64
 
59
65
  It allows many tags to be accessed in audio format, and tag format independent way.
60
66
 
@@ -64,38 +70,16 @@ Support for [MusicBrainz](https://musicbrainz.org/) tags as written by [Picard](
64
70
  ### Audio format & encoding details
65
71
 
66
72
  Support for encoding / format details:
67
- * [Bit rate](https://wikipedia.org/wiki/Bit_rate)
68
- * [Audio bit depth](https://wikipedia.org/wiki/Audio_bit_depth)
69
- * Duration
70
- * Encoding profile (e.g. [CBR](https://en.wikipedia.org/wiki/Constant_bitrate), V0, V2)
71
-
72
-
73
- ## Online demo's
74
- * [<img src="https://raw.githubusercontent.com/Borewit/audio-tag-analyzer/master/src/assets/icon/audio-tag-analyzer.svg" width="40">Audio Tag Analyzer](https://audio-tag-analyzer.netlify.com/)
75
- * [<img src="https://cdn.sanity.io/images/3do82whm/next/ba8c847f13a5fa39d88f8bc9b7846b7886531b18-2500x2500.svg" width="40"> Webamp](https://webamp.org/)
76
-
77
-
78
- ## Compatibility
79
-
80
- Module: version 8 migrated from [CommonJS](https://en.wikipedia.org/wiki/CommonJS) to [pure ECMAScript Module (ESM)](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
81
- JavaScript is compliant with [ECMAScript 2019 (ES10)](https://en.wikipedia.org/wiki/ECMAScript#10th_Edition_%E2%80%93_ECMAScript_2019).
82
- Requires Node.js ≥ 14.13.1 engine.
83
-
84
- ### Browser Support
73
+ * [Bit rate](https://wikipedia.org/wiki/Bit_rate)
74
+ * [Audio bit depth](https://wikipedia.org/wiki/Audio_bit_depth)
75
+ * Duration
76
+ * Encoding profile (e.g. [CBR](https://en.wikipedia.org/wiki/Constant_bitrate), V0, V2)
85
77
 
86
- Although music-metadata is designed to run the node.js. [music-metadata-browser](https://github.com/Borewit/music-metadata-browser) can be used on the browser side.
87
78
 
88
- To avoid Node `fs` dependency inclusion, you may use a sub-module inclusion:
89
- ```js
90
- import * as mm from 'music-metadata/lib/core';
91
- ```
79
+ ## Online demo's
80
+ * [<img src="https://raw.githubusercontent.com/Borewit/audio-tag-analyzer/master/src/assets/icon/audio-tag-analyzer.svg" width="40">Audio Tag Analyzer](https://https://audio-tag-analyzer.netlify.app/)
81
+ * [<img src="https://cdn.sanity.io/images/3do82whm/next/ba8c847f13a5fa39d88f8bc9b7846b7886531b18-2500x2500.svg" width="40"> Webamp](https://webamp.org/)
92
82
 
93
- | function | `music-metadata` | `music-metadata/lib/core` |
94
- |------------------------------------------------------| ---------------------------|----------------------------|
95
- | [`parseBuffer`](#parsebuffer-function) | ✓ | ✓ |
96
- | [`parseStream`](#parsestream-function) * | ✓ | ✓ |
97
- | [`parseFromTokenizer`](#parsefromtokenizer-function) | ✓ | ✓ |
98
- | [`parseFile`](#parsefile-function) | ✓ | |
99
83
 
100
84
  ### Sponsor
101
85
  [Become a sponsor to Borewit](https://github.com/sponsors/Borewit)
@@ -105,28 +89,26 @@ import * as mm from 'music-metadata/lib/core';
105
89
  Dependency diagram:
106
90
  ```mermaid
107
91
  graph TD;
108
- MM(music-metadata)-->S(strtok3)
109
- MM-->TY(token-types)
110
- MM-->FT(file-type)
92
+ MMN("music-metadata (Node.js entry point)")-->MMP
93
+ MMN-->FTN
94
+ MMP("music-metadata (primary entry point)")-->S(strtok3)
95
+ MMP-->TY(token-types)
96
+ MMP-->FTP
97
+ MMP-->UAE
98
+ FTN("file-type (Node.js entry point)")-->FTP
99
+ FTP("file-type (primary entry point)")-->S
111
100
  S(strtok3)-->P(peek-readable)
112
- S-->TO("@tokenizer/token")
113
- TY-->TO
101
+ S(strtok3)-->TO("@tokenizer/token")
102
+ TY(token-types)-->TO
114
103
  TY-->IE("ieee754")
115
- FT-->RWNS(readable-web-to-node-stream)
116
- FT-->S
117
- FT-->TY
118
- TY-->NB(node:buffer)
119
- RWNS-->RS(readable-stream)
120
- RS-->SD(string_decoder)
121
- SD-->SB(safe-buffer)
122
- RS-->UD(util-deprecate)
123
- RS-->I(inherits)
124
- style NB fill:#F88,stroke:#A44
125
- style SB fill:#F88,stroke:#A44
126
- style SD fill:#CCC,stroke:#888
104
+ FTP-->TY
105
+ NS("node:stream")
106
+ FTN-->NS
107
+ FTP-->UAE(uint8array-extras)
108
+ style NS fill:#F88,stroke:#A44
127
109
  style IE fill:#CCC,stroke:#888
128
- style UD fill:#CCC,stroke:#888
129
- style I fill:#CCC,stroke:#888
110
+ style FTN fill:#FAA,stroke:#A44
111
+ style MMN fill:#FAA,stroke:#A44
130
112
  ```
131
113
 
132
114
  Dependency list:
@@ -192,8 +174,11 @@ import { inspect } from 'util';
192
174
 
193
175
  #### parseStream function
194
176
 
177
+ _Only available for Node.js._
178
+
195
179
  Parses the provided audio stream for metadata.
196
- It is recommended to provide the corresponding [MIME-type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types).
180
+ The stream should be of type [Node.js Readable](https://nodejs.org/api/stream.html#class-streamreadable).
181
+ It is recommended to provide the corresponding [MIME-type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types).
197
182
  An extension (e.g.: `.mp3`), filename or path will also work.
198
183
  If the MIME-type or filename (via `fileInfo.path`) is not provided, or not understood, music-metadata will try to derive the type from the content.
199
184
 
@@ -215,6 +200,41 @@ import { parseStream } from 'music-metadata';
215
200
  })();
216
201
  ```
217
202
 
203
+ #### parseWebStream function
204
+
205
+ Parses the provided audio web stream for metadata.
206
+ The stream should be of type [ReadableStream<Uint8Array>](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream).
207
+ It is recommended to provide the corresponding [MIME-type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types).
208
+ An extension (e.g.: `.mp3`), filename or path will also work.
209
+ If the MIME-type or filename (via `fileInfo.path`) is not provided, or not understood, music-metadata will try to derive the type from the content.
210
+
211
+ ```ts
212
+ parseWebStream(stream: ReadableStream<Uint8Array>, fileInfo?: IFileInfo | string, opts?: IOptions = {}): Promise<IAudioMetadata>`
213
+ ```
214
+
215
+ #### parseBlob function
216
+
217
+ Parse an audio file from a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) or [File](https://developer.mozilla.org/en-US/docs/Web/API/File).
218
+
219
+ ```js
220
+ const musicMetadata = require('music-metadata');
221
+
222
+ let blob;
223
+
224
+ musicMetadata.parseBlob(blob).then(metadata => {
225
+ // metadata has all the metadata found in the blob or file
226
+ });
227
+ ```
228
+ Or with async/await if you prefer:
229
+ ```js
230
+ (async () => {
231
+ let blob; // File or Blob
232
+
233
+ const metadata = await musicMetadata.parseBlob(blob);
234
+ // metadata has all the metadata found in the blob or file
235
+ });
236
+ ```
237
+
218
238
  #### parseBuffer function
219
239
 
220
240
  Parse metadata from an audio file, where the audio file is held in a [Buffer](https://nodejs.org/api/buffer.html).
@@ -242,7 +262,7 @@ This is a low level function, reading from a [strtok3](https://github.com/Borewi
242
262
  [music-metadata-browser](https://github.com/Borewit/music-metadata-browser) is depended on this function.
243
263
 
244
264
  This also enables special read modules like:
245
- * [streaming-http-token-reader](https://github.com/Borewit/streaming-http-token-reader) for chunked HTTP(S) reading, using [HTTP range requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests).
265
+ * [streaming-http-token-reader](https://github.com/Borewit/streaming-http-token-reader) for chunked HTTP(S) reading, using [HTTP range requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests).
246
266
 
247
267
  #### orderTags function
248
268
 
@@ -268,9 +288,9 @@ import { inspect } from 'util';
268
288
  ```
269
289
 
270
290
  #### ratingToStars function
271
-
291
+
272
292
  Can be used to convert the normalized rating value to the 0..5 stars, where 0 an undefined rating, 1 the star the lowest rating and 5 the highest rating.
273
-
293
+
274
294
  ```ts
275
295
  ratingToStars(rating: number): number
276
296
  ```
@@ -293,84 +313,84 @@ import { parseFile, selectCover } from 'music-metadata';
293
313
  ```
294
314
 
295
315
  ### Options
296
- * `duration`: default: `false`, if set to `true`, it will parse the whole media file if required to determine the duration.
297
- * `observer: (update: MetadataEvent) => void;`: Will be called after each change to `common` (generic) tag, or `format` properties.
298
- * `skipCovers`: default: `false`, if set to `true`, it will not return embedded cover-art (images).
299
- * `skipPostHeaders? boolean` default: `false`, if set to `true`, it will not search all the entire track for additional headers. Only recommenced to use in combination with streams.
300
- * `includeChapters` default: `false`, if set to `true`, it will parse chapters (currently only MP4 files). _experimental functionality_
316
+ - `duration`: default: `false`, if set to `true`, it will parse the whole media file if required to determine the duration.
317
+ - `observer: (update: MetadataEvent) => void;`: Will be called after each change to `common` (generic) tag, or `format` properties.
318
+ - `skipCovers`: default: `false`, if set to `true`, it will not return embedded cover-art (images).
319
+ - `skipPostHeaders? boolean` default: `false`, if set to `true`, it will not search all the entire track for additional headers. Only recommenced to use in combination with streams.
320
+ - `includeChapters` default: `false`, if set to `true`, it will parse chapters (currently only MP4 files). _experimental functionality_
301
321
 
302
322
  Although in most cases duration is included, in some cases it requires `music-metadata` parsing the entire file.
303
323
  To enforce parsing the entire file if needed you should set `duration` to `true`.
304
-
324
+
305
325
  ### Metadata result
306
326
 
307
327
  If the returned promise resolves, the metadata (TypeScript `IAudioMetadata` interface) contains:
308
- * [`metadata.format`](#metadataformat) Audio format information
309
- * [`metadata.common`](#metadatacommon) Is a generic (abstract) way of reading metadata information.
310
- * [`metadata.trackInfo`](#metadatatrackInfo) Is a generic (abstract) way of reading metadata information.
311
- * `metadata.native` List of native (original) tags found in the parsed audio file.
312
-
328
+ - [`metadata.format`](#metadataformat) Audio format information
329
+ - [`metadata.common`](#metadatacommon) Is a generic (abstract) way of reading metadata information.
330
+ - [`metadata.trackInfo`](#metadatatrackInfo) Is a generic (abstract) way of reading metadata information.
331
+ - `metadata.native` List of native (original) tags found in the parsed audio file.
332
+
313
333
  #### `metadata.format`
314
334
 
315
- The questionmark `?` indicates the property is optional.
316
-
335
+ The questionmark `?` indicates the property is optional.
336
+
317
337
  Audio format information. Defined in the TypeScript `IFormat` interface:
318
- * `format.container?: string` Audio encoding format. e.g.: 'flac'
319
- * `format.codec?` Name of the codec (algorithm used for the audio compression)
320
- * `format.codecProfile?: string` Codec profile / settings
321
- * `format.tagTypes?: TagType[]` List of tagging formats found in parsed audio file
322
- * `format.duration?: number` Duration in seconds
323
- * `format.bitrate?: number` Number bits per second of encoded audio file
324
- * `format.sampleRate?: number` Sampling rate in Samples per second (S/s)
325
- * `format.bitsPerSample?: number` Audio bit depth
326
- * `format.lossless?: boolean` True if lossless, false for lossy encoding
327
- * `format.numberOfChannels?: number` Number of audio channels
328
- * `format.creationTime?: Date` Track creation time
329
- * `format.modificationTime?: Date` Track modification / tag update time
330
- * `format.trackGain?: number` Track gain in dB
331
- * `format.albumGain?: number` Album gain in dB
338
+ - `format.container?: string` Audio encoding format. e.g.: 'flac'
339
+ - `format.codec?` Name of the codec (algorithm used for the audio compression)
340
+ - `format.codecProfile?: string` Codec profile / settings
341
+ - `format.tagTypes?: TagType[]` List of tagging formats found in parsed audio file
342
+ - `format.duration?: number` Duration in seconds
343
+ - `format.bitrate?: number` Number bits per second of encoded audio file
344
+ - `format.sampleRate?: number` Sampling rate in Samples per second (S/s)
345
+ - `format.bitsPerSample?: number` Audio bit depth
346
+ - `format.lossless?: boolean` True if lossless, false for lossy encoding
347
+ - `format.numberOfChannels?: number` Number of audio channels
348
+ - `format.creationTime?: Date` Track creation time
349
+ - `format.modificationTime?: Date` Track modification / tag update time
350
+ - `format.trackGain?: number` Track gain in dB
351
+ - `format.albumGain?: number` Album gain in dB
332
352
 
333
353
  #### `metadata.trackInfo`
334
354
 
335
- To support advanced containers like [Matroska](https://wikipedia.org/wiki/Matroska) or [MPEG-4](https://en.wikipedia.org/wiki/MPEG-4), which may contain multiple audio and video tracks, the **experimental** `metadata.trackInfo` has been added,
336
-
355
+ To support advanced containers like [Matroska](https://wikipedia.org/wiki/Matroska) or [MPEG-4](https://en.wikipedia.org/wiki/MPEG-4), which may contain multiple audio and video tracks, the **experimental*- `metadata.trackInfo` has been added,
356
+
337
357
  `metadata.trackInfo` is either `undefined` or has an **array** of [trackInfo](#trackinfo)
338
-
358
+
339
359
  ##### trackInfo
340
-
360
+
341
361
  Audio format information. Defined in the TypeScript `IFormat` interface:
342
- * `trackInfo.type?: TrackType` Track type
343
- * `trackInfo.codecName?: string` Codec name
344
- * `trackInfo.codecSettings?: string` Codec settings
345
- * `trackInfo.flagEnabled?: boolean` Set if the track is usable, default: `true`
346
- * `trackInfo.flagDefault?: boolean` Set if that track (audio, video or subs) SHOULD be active if no language found matches the user preference.
347
- * `trackInfo.flagLacing?: boolean` Set if the track **may** contain blocks using lacing
348
- * `trackInfo.name?: string` A human-readable track name.
349
- * `trackInfo.language?: string` Specifies the language of the track
350
- * `trackInfo.audio?: IAudioTrack`, see [`trackInfo.audioTrack`](#trackinfoaudiotrack)
351
- * `trackInfo.video?: IVideoTrack`, see [`trackInfo.videoTrack`](#trackinfovideotrack)
362
+ - `trackInfo.type?: TrackType` Track type
363
+ - `trackInfo.codecName?: string` Codec name
364
+ - `trackInfo.codecSettings?: string` Codec settings
365
+ - `trackInfo.flagEnabled?: boolean` Set if the track is usable, default: `true`
366
+ - `trackInfo.flagDefault?: boolean` Set if that track (audio, video or subs) SHOULD be active if no language found matches the user preference.
367
+ - `trackInfo.flagLacing?: boolean` Set if the track **may** contain blocks using lacing
368
+ - `trackInfo.name?: string` A human-readable track name.
369
+ - `trackInfo.language?: string` Specifies the language of the track
370
+ - `trackInfo.audio?: IAudioTrack`, see [`trackInfo.audioTrack`](#trackinfoaudiotrack)
371
+ - `trackInfo.video?: IVideoTrack`, see [`trackInfo.videoTrack`](#trackinfovideotrack)
352
372
 
353
373
  ##### `trackInfo.audioTrack`
354
374
 
355
- * `audioTrack.samplingFrequency?: number`
356
- * `audioTrack.outputSamplingFrequency?: number`
357
- * `audioTrack.channels?: number`
358
- * `audioTrack.channelPositions?: Buffer`
359
- * `audioTrack.bitDepth?: number`
375
+ - `audioTrack.samplingFrequency?: number`
376
+ - `audioTrack.outputSamplingFrequency?: number`
377
+ - `audioTrack.channels?: number`
378
+ - `audioTrack.channelPositions?: Buffer`
379
+ - `audioTrack.bitDepth?: number`
360
380
 
361
381
  ##### `trackInfo.videoTrack`
362
382
 
363
- * `videoTrack.flagInterlaced?: boolean`
364
- * `videoTrack.stereoMode?: number`
365
- * `videoTrack.pixelWidth?: number`
366
- * `videoTrack.pixelHeight?: number`
367
- * `videoTrack.displayWidth?: number`
368
- * `videoTrack.displayHeight?: number`
369
- * `videoTrack.displayUnit?: number`
370
- * `videoTrack.aspectRatioType?: number`
371
- * `videoTrack.colourSpace?: Buffer`
372
- * `videoTrack.gammaValue?: number`
373
-
383
+ - `videoTrack.flagInterlaced?: boolean`
384
+ - `videoTrack.stereoMode?: number`
385
+ - `videoTrack.pixelWidth?: number`
386
+ - `videoTrack.pixelHeight?: number`
387
+ - `videoTrack.displayWidth?: number`
388
+ - `videoTrack.displayHeight?: number`
389
+ - `videoTrack.displayUnit?: number`
390
+ - `videoTrack.aspectRatioType?: number`
391
+ - `videoTrack.colourSpace?: Buffer`
392
+ - `videoTrack.gammaValue?: number`
393
+
374
394
  #### `metadata.common`
375
395
 
376
396
  [Common tag documentation](doc/common_metadata.md) is automatically generated.
@@ -436,11 +456,11 @@ img.src = `data:${picture.format};base64,${picture.data.toString('base64')}`;
436
456
 
437
457
  ```js
438
458
  import { parseFile } from 'music-metadata';
439
-
459
+
440
460
  function parseFiles(audioFiles) {
441
-
461
+
442
462
  const audioFile = audioFiles.shift();
443
-
463
+
444
464
  if (audioFile) {
445
465
  return parseFile(audioFile).then(metadata => {
446
466
  // Do great things with the metadata
@@ -448,21 +468,21 @@ img.src = `data:${picture.format};base64,${picture.data.toString('base64')}`;
448
468
  })
449
469
  }
450
470
  }
451
-
471
+
452
472
  ```
453
473
 
454
474
  2. Use async/await
455
-
475
+
456
476
  Use [async/await](https://javascript.info/async-await)
457
-
477
+
458
478
  ```js
459
479
  import { parseFile } from 'music-metadata';
460
-
480
+
461
481
  // it is required to declare the function 'async' to allow the use of await
462
482
  async function parseFiles(audioFiles) {
463
-
483
+
464
484
  for (const audioFile of audioFiles) {
465
-
485
+
466
486
  // await will ensure the metadata parsing is completed before we move on to the next file
467
487
  const metadata = await parseFile(audioFile);
468
488
  // Do great things with the metadata
@@ -1,6 +1,6 @@
1
1
  import { INativeMetadataCollector } from './common/MetadataCollector.js';
2
2
  import { IOptions, IAudioMetadata, ParserType } from './type.js';
3
- import { ITokenizer } from 'strtok3/core';
3
+ import type { ITokenizer } from 'strtok3';
4
4
  export interface ITokenParser {
5
5
  /**
6
6
  * Initialize parser with output (metadata), input (tokenizer) & parsing options (options).
@@ -2,7 +2,6 @@ import { fileTypeFromBuffer } from 'file-type';
2
2
  import ContentType from 'content-type';
3
3
  import MimeType from 'media-typer';
4
4
  import initDebug from 'debug';
5
- import { Buffer } from 'node:buffer';
6
5
  import { MetadataCollector } from './common/MetadataCollector.js';
7
6
  import { AIFFParser } from './aiff/AiffParser.js';
8
7
  import { APEv2Parser } from './apev2/APEv2Parser.js';
@@ -55,7 +54,7 @@ export class ParserFactory {
55
54
  if (!parserId) {
56
55
  // Parser could not be determined on MIME-type or extension
57
56
  debug('Guess parser on content...');
58
- const buf = Buffer.alloc(4100);
57
+ const buf = new Uint8Array(4100);
59
58
  await tokenizer.peekBuffer(buf, { mayBeLess: true });
60
59
  if (tokenizer.fileInfo.path) {
61
60
  parserId = this.getParserIdForExtension(tokenizer.fileInfo.path);
@@ -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 { ID3v2Parser } from '../id3v2/ID3v2Parser.js';
5
5
  import { FourCcToken } from '../common/FourCC.js';
6
6
  import { BasicParser } from '../common/BasicParser.js';
@@ -96,9 +96,8 @@ export class AIFFParser extends BasicParser {
96
96
  }
97
97
  async readTextChunk(header) {
98
98
  const value = await this.tokenizer.readToken(new Token.StringType(header.chunkSize, 'ascii'));
99
- value.split('\0').map(v => v.trim()).filter(v => v && v.length > 0).forEach(v => {
100
- this.metadata.addTag('AIFF', header.chunkID, v.trim());
101
- });
99
+ const values = value.split('\0').map(v => v.trim()).filter(v => v && v.length);
100
+ await Promise.all(values.map(v => this.metadata.addTag('AIFF', header.chunkID, v)));
102
101
  return header.chunkSize;
103
102
  }
104
103
  }
@@ -1,7 +1,5 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import { Buffer } from 'node:buffer';
3
1
  import * as iff from '../iff/index.js';
4
- import { IGetToken } from 'strtok3';
2
+ import type { IGetToken } from 'strtok3';
5
3
  /**
6
4
  * The Common Chunk.
7
5
  * Describes fundamental parameters of the waveform data such as sample rate, bit resolution, and how many channels of
@@ -19,5 +17,5 @@ export declare class Common implements IGetToken<ICommon> {
19
17
  private isAifc;
20
18
  len: number;
21
19
  constructor(header: iff.IChunkHeader, isAifc: boolean);
22
- get(buf: Buffer, off: number): ICommon;
20
+ get(buf: Uint8Array, off: number): ICommon;
23
21
  }
@@ -10,22 +10,22 @@ export class Common {
10
10
  }
11
11
  get(buf, off) {
12
12
  // see: https://cycling74.com/forums/aiffs-80-bit-sample-rate-value
13
- const shift = buf.readUInt16BE(off + 8) - 16398;
14
- const baseSampleRate = buf.readUInt16BE(off + 8 + 2);
13
+ const shift = Token.UINT16_BE.get(buf, off + 8) - 16398;
14
+ const baseSampleRate = Token.UINT16_BE.get(buf, off + 8 + 2);
15
15
  const res = {
16
- numChannels: buf.readUInt16BE(off),
17
- numSampleFrames: buf.readUInt32BE(off + 2),
18
- sampleSize: buf.readUInt16BE(off + 6),
16
+ numChannels: Token.UINT16_BE.get(buf, off),
17
+ numSampleFrames: Token.UINT32_BE.get(buf, off + 2),
18
+ sampleSize: Token.UINT16_BE.get(buf, off + 6),
19
19
  sampleRate: shift < 0 ? baseSampleRate >> Math.abs(shift) : baseSampleRate << shift
20
20
  };
21
21
  if (this.isAifc) {
22
22
  res.compressionType = FourCcToken.get(buf, off + 18);
23
23
  if (this.len > 22) {
24
- const strLen = buf.readInt8(off + 22);
24
+ const strLen = Token.UINT8.get(buf, off + 22);
25
25
  if (strLen > 0) {
26
26
  const padding = (strLen + 1) % 2;
27
27
  if (23 + strLen + padding === this.len) {
28
- res.compressionName = new Token.StringType(strLen, 'binary').get(buf, off + 23);
28
+ res.compressionName = new Token.StringType(strLen, 'latin1').get(buf, off + 23);
29
29
  }
30
30
  else {
31
31
  throw new Error('Illegal pstring length');
@@ -1,4 +1,4 @@
1
- import * as strtok3 from 'strtok3/core';
1
+ import * as strtok3 from 'strtok3';
2
2
  import { IOptions, IRandomReader, IApeHeader } from '../type.js';
3
3
  import { INativeMetadataCollector } from '../common/MetadataCollector.js';
4
4
  import { BasicParser } from '../common/BasicParser.js';
@@ -1,7 +1,7 @@
1
1
  import initDebug from 'debug';
2
- import * as strtok3 from 'strtok3/core';
2
+ import * as strtok3 from 'strtok3';
3
3
  import { StringType } from 'token-types';
4
- import { Buffer } from 'node:buffer';
4
+ import { uint8ArrayToString } from 'uint8array-extras';
5
5
  import * as util from '../common/Util.js';
6
6
  import { BasicParser } from '../common/BasicParser.js';
7
7
  import { DataType, DescriptorParser, Header, TagFooter, TagItemHeader } from './APEv2Token.js';
@@ -35,7 +35,7 @@ export class APEv2Parser extends BasicParser {
35
35
  */
36
36
  static async findApeFooterOffset(reader, offset) {
37
37
  // Search for APE footer header at the end of the file
38
- const apeBuf = Buffer.alloc(TagFooter.len);
38
+ const apeBuf = new Uint8Array(TagFooter.len);
39
39
  await reader.randomRead(apeBuf, 0, TagFooter.len, offset - TagFooter.len);
40
40
  const tagFooter = TagFooter.get(apeBuf, 0);
41
41
  if (tagFooter.ID === 'APETAGEX') {
@@ -70,7 +70,7 @@ export class APEv2Parser extends BasicParser {
70
70
  if (this.tokenizer.fileInfo.size) {
71
71
  // Try to read the APEv2 header using just the footer-header
72
72
  const remaining = this.tokenizer.fileInfo.size - this.tokenizer.position; // ToDo: take ID3v1 into account
73
- const buffer = Buffer.alloc(remaining);
73
+ const buffer = new Uint8Array(remaining);
74
74
  await this.tokenizer.readBuffer(buffer);
75
75
  return APEv2Parser.parseTagFooter(this.metadata, buffer, this.options);
76
76
  }
@@ -87,7 +87,7 @@ export class APEv2Parser extends BasicParser {
87
87
  return this.tryParseApeHeader();
88
88
  }
89
89
  async parseTags(footer) {
90
- const keyBuffer = Buffer.alloc(256); // maximum tag key length
90
+ const keyBuffer = new Uint8Array(256); // maximum tag key length
91
91
  let bytesRemaining = footer.size - TagFooter.len;
92
92
  debug(`Parse APE tags at offset=${this.tokenizer.position}, size=${bytesRemaining}`);
93
93
  for (let i = 0; i < footer.fields; i++) {
@@ -107,9 +107,7 @@ export class APEv2Parser extends BasicParser {
107
107
  case DataType.text_utf8: { // utf-8 text-string
108
108
  const value = await this.tokenizer.readToken(new StringType(tagItemHeader.size, 'utf8'));
109
109
  const values = value.split(/\x00/g);
110
- for (const val of values) {
111
- this.metadata.addTag(tagFormat, key, val);
112
- }
110
+ await Promise.all(values.map(val => this.metadata.addTag(tagFormat, key, val)));
113
111
  break;
114
112
  }
115
113
  case DataType.binary: // binary (probably artwork)
@@ -117,12 +115,12 @@ export class APEv2Parser extends BasicParser {
117
115
  await this.tokenizer.ignore(tagItemHeader.size);
118
116
  }
119
117
  else {
120
- const picData = Buffer.alloc(tagItemHeader.size);
118
+ const picData = new Uint8Array(tagItemHeader.size);
121
119
  await this.tokenizer.readBuffer(picData);
122
120
  zero = util.findZero(picData, 0, picData.length);
123
- const description = picData.toString('utf8', 0, zero);
124
- const data = Buffer.from(picData.slice(zero + 1));
125
- this.metadata.addTag(tagFormat, key, {
121
+ const description = uint8ArrayToString(picData.slice(0, zero));
122
+ const data = picData.slice(zero + 1);
123
+ await this.metadata.addTag(tagFormat, key, {
126
124
  description,
127
125
  data
128
126
  });
@@ -1,5 +1,5 @@
1
1
  import * as Token from 'token-types';
2
- import { IGetToken } from 'strtok3/core';
2
+ import type { IGetToken } from 'strtok3';
3
3
  /**
4
4
  * APETag versionIndex history / supported formats
5
5
  *