music-metadata 10.2.0 → 10.3.1
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.
- package/README.md +435 -126
- package/lib/ParseError.d.ts +87 -0
- package/lib/ParseError.js +39 -0
- package/lib/ParserFactory.d.ts +1 -1
- package/lib/ParserFactory.js +8 -7
- package/lib/aiff/AiffParser.js +4 -4
- package/lib/aiff/AiffToken.d.ts +15 -0
- package/lib/aiff/AiffToken.js +5 -2
- package/lib/apev2/APEv2Parser.d.ts +15 -0
- package/lib/apev2/APEv2Parser.js +6 -3
- package/lib/asf/AsfObject.d.ts +15 -0
- package/lib/asf/AsfObject.js +4 -1
- package/lib/asf/AsfParser.js +2 -1
- package/lib/common/CombinedTagMapper.js +2 -1
- package/lib/common/FourCC.js +3 -2
- package/lib/common/Util.js +3 -2
- package/lib/core.d.ts +3 -1
- package/lib/core.js +1 -1
- package/lib/default.cjs +5 -0
- package/lib/dsdiff/DsdiffParser.d.ts +15 -0
- package/lib/dsdiff/DsdiffParser.js +6 -3
- package/lib/dsf/DsfParser.d.ts +15 -0
- package/lib/dsf/DsfParser.js +4 -1
- package/lib/ebml/EbmlIterator.d.ts +15 -0
- package/lib/ebml/EbmlIterator.js +5 -2
- package/lib/flac/FlacParser.js +5 -2
- package/lib/id3v2/FrameParser.d.ts +14 -0
- package/lib/id3v2/FrameParser.js +7 -1
- package/lib/id3v2/ID3v2Parser.js +8 -5
- package/lib/mp4/AtomToken.d.ts +14 -0
- package/lib/mp4/AtomToken.js +6 -3
- package/lib/mp4/MP4Parser.js +4 -3
- package/lib/mpeg/MpegParser.d.ts +15 -0
- package/lib/mpeg/MpegParser.js +7 -4
- package/lib/musepack/MusepackConentError.d.ts +15 -0
- package/lib/musepack/MusepackConentError.js +4 -0
- package/lib/musepack/index.js +4 -3
- package/lib/musepack/sv7/MpcSv7Parser.js +2 -1
- package/lib/musepack/sv8/MpcSv8Parser.js +3 -2
- package/lib/node.cjs +5 -0
- package/lib/ogg/OggParser.d.ts +15 -0
- package/lib/ogg/OggParser.js +5 -2
- package/lib/ogg/opus/Opus.d.ts +15 -0
- package/lib/ogg/opus/Opus.js +4 -1
- package/lib/ogg/opus/OpusParser.js +2 -1
- package/lib/ogg/vorbis/VorbisParser.d.ts +15 -0
- package/lib/ogg/vorbis/VorbisParser.js +6 -3
- package/lib/wav/WaveChunk.d.ts +15 -0
- package/lib/wav/WaveChunk.js +5 -2
- package/lib/wav/WaveParser.js +3 -2
- package/lib/wavpack/WavPackParser.d.ts +15 -0
- package/lib/wavpack/WavPackParser.js +6 -3
- package/package.json +16 -7
package/README.md
CHANGED
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
# music-metadata
|
|
13
13
|
|
|
14
14
|
Key features:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
- **Comprehensive Format Support**: Supports popular audio formats like MP3, MP4, FLAC, Ogg, WAV, AIFF, and more.
|
|
16
|
+
- **Extensive Metadata Extraction**: Extracts detailed metadata, including ID3v1, ID3v2, APE, Vorbis, and iTunes/MP4 tags.
|
|
17
|
+
- **Streaming Support**: Efficiently handles large audio files by reading metadata from streams, making it suitable for server-side and browser-based applications.
|
|
18
|
+
- **Promise-Based API**: Provides a modern, promise-based API for easy integration into asynchronous workflows.
|
|
19
|
+
- **Cross-Platform**: Works in both [Node.js](https://nodejs.org/) and browser environments with the help of bundlers like [Webpack](https://webpack.js.org/) or [Rollup](https://rollupjs.org/introduction/).
|
|
20
20
|
|
|
21
21
|
The [`music-metadata`](https://github.com/Borewit/music-metadata) module is ideal for developers working on media applications, music players, or any project that requires access to detailed audio file metadata.
|
|
22
22
|
|
|
@@ -25,6 +25,9 @@ The [`music-metadata`](https://github.com/Borewit/music-metadata) module is idea
|
|
|
25
25
|
Module: version 8 migrated from [CommonJS](https://en.wikipedia.org/wiki/CommonJS) to [pure ECMAScript Module (ESM)](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
|
|
26
26
|
The distributed JavaScript codebase is compliant with the [ECMAScript 2020 (11th Edition)](https://en.wikipedia.org/wiki/ECMAScript_version_history#11th_Edition_%E2%80%93_ECMAScript_2020) standard.
|
|
27
27
|
|
|
28
|
+
> [!NOTE]
|
|
29
|
+
> See also [CommonJS Backward Compatibility](#commonjs-backward-compatibility)
|
|
30
|
+
|
|
28
31
|
This module requires a [Node.js ≥ 16](https://nodejs.org/en/about/previous-releases) engine.
|
|
29
32
|
It can also be used in a browser environment when bundled with a module bundler.
|
|
30
33
|
|
|
@@ -95,43 +98,7 @@ Support for encoding / format details:
|
|
|
95
98
|
## Online demo's
|
|
96
99
|
- [<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.app/)
|
|
97
100
|
- [<img src="https://cdn.sanity.io/images/3do82whm/next/ba8c847f13a5fa39d88f8bc9b7846b7886531b18-2500x2500.svg" width="40"> Webamp](https://webamp.org/)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
## Dependencies
|
|
101
|
-
|
|
102
|
-
Dependency diagram:
|
|
103
|
-
```mermaid
|
|
104
|
-
graph TD;
|
|
105
|
-
MMN("music-metadata (Node.js entry point)")-->MMP
|
|
106
|
-
MMN-->FTN
|
|
107
|
-
MMP("music-metadata (primary entry point)")-->S(strtok3)
|
|
108
|
-
MMP-->TY(token-types)
|
|
109
|
-
MMP-->FTP
|
|
110
|
-
MMP-->UAE
|
|
111
|
-
FTN("file-type (Node.js entry point)")-->FTP
|
|
112
|
-
FTP("file-type (primary entry point)")-->S
|
|
113
|
-
S(strtok3)-->P(peek-readable)
|
|
114
|
-
S(strtok3)-->TO("@tokenizer/token")
|
|
115
|
-
TY(token-types)-->TO
|
|
116
|
-
TY-->IE("ieee754")
|
|
117
|
-
FTP-->TY
|
|
118
|
-
NS("node:stream")
|
|
119
|
-
FTN-->NS
|
|
120
|
-
FTP-->UAE(uint8array-extras)
|
|
121
|
-
style NS fill:#F88,stroke:#A44
|
|
122
|
-
style IE fill:#CCC,stroke:#888
|
|
123
|
-
style FTN fill:#FAA,stroke:#A44
|
|
124
|
-
style MMN fill:#FAA,stroke:#A44
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Dependency list:
|
|
128
|
-
- [tokenizer-token](https://github.com/Borewit/tokenizer-token)
|
|
129
|
-
- [strtok3](https://github.com/Borewit/strtok3)
|
|
130
|
-
- [token-types](https://github.com/Borewit/token-types)
|
|
131
|
-
- [file-type](https://github.com/sindresorhus/file-type)
|
|
132
|
-
- [@tokenizer-token](https://github.com/Borewit/tokenizer-token)
|
|
133
|
-
- [peek-readable](https://github.com/Borewit/peek-readable)
|
|
134
|
-
- [readable-web-to-node-stream](https://github.com/Borewit/readable-web-to-node-stream)
|
|
101
|
+
- Expected to be released soon: [Overtone](https://overtone.pro/) by [Johannes Schickling](https://github.com/schickling)
|
|
135
102
|
|
|
136
103
|
## Usage
|
|
137
104
|
|
|
@@ -146,146 +113,428 @@ or using [yarn](https://yarnpkg.com/):
|
|
|
146
113
|
yarn add music-metadata
|
|
147
114
|
```
|
|
148
115
|
|
|
149
|
-
|
|
116
|
+
## API Documentation
|
|
150
117
|
|
|
151
|
-
|
|
152
|
-
```JavaScript
|
|
153
|
-
import { parseFile } from 'music-metadata';
|
|
154
|
-
```
|
|
155
|
-
Import the methods you need, like `parseFile` in this example.
|
|
118
|
+
### Overview
|
|
156
119
|
|
|
157
|
-
|
|
120
|
+
**Node.js specific** functions to read an audio file or stream:
|
|
121
|
+
1. **File Parsing**: Parse audio files directly from the filesystem using the [parseFile function](#parsefile-function)
|
|
122
|
+
1. **Stream Parsing**: Parse audio metadata from a Node.js [Readable stream](https://nodejs.org/api/stream.html#class-streamreadable) using the [parseStream function](#parsewebstream-function).
|
|
123
|
+
|
|
124
|
+
**Cross-platform** functions available to read an audio file or stream:
|
|
158
125
|
|
|
159
126
|
There are multiple ways to parse (read) audio tracks:
|
|
160
|
-
1.
|
|
161
|
-
1.
|
|
162
|
-
1.
|
|
163
|
-
1.
|
|
164
|
-
1. Via your own, or a third-party [strtok3](https://github.com/Borewit/strtok3) ITokenizer using the [parseFromTokenizer function](#parsefromtokenizer-function).
|
|
127
|
+
1. **Web Stream Parsing**: Parse audio data from a web-compatible [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream) using the [parseWebStream function](#parsewebstream-function).
|
|
128
|
+
1. **Blob Parsing**: Parse audio metadata from a (Web API) [Blob](https://developer.mozilla.org/docs/Web/API/Blob) or [File](https://developer.mozilla.org/docs/Web/API/File) using the [parseBlob function](#parseblob-function).
|
|
129
|
+
1. **Buffer Parsing**: Parse audio metadata from a [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) or [Buffer](https://nodejs.org/api/buffer.html) using the [parseBuffer function](#parsebuffer-function).
|
|
130
|
+
1. **Tokenizer Parsing:** Use a custom or third-party [strtok3](https://github.com/Borewit/strtok3) `ITokenizer` to parse using the [parseFromTokenizer function](#parsefromtokenizer-function).
|
|
165
131
|
|
|
166
|
-
|
|
132
|
+
> [!NOTE]
|
|
133
|
+
> Direct file access in Node.js is generally faster because it can 'jump' to various parts of the file without reading intermediate data.
|
|
167
134
|
|
|
168
|
-
|
|
135
|
+
### Node.js specific function
|
|
136
|
+
These functions are tailored for Node.js environments and leverage Node.js-specific APIs,
|
|
137
|
+
making them incompatible with browser-based JavaScript engines.
|
|
169
138
|
|
|
170
|
-
|
|
171
|
-
To read from a [File](https://developer.mozilla.org/docs/Web/API/File),
|
|
172
|
-
please see [fileTypeFromBlob(blob)](#parseblob-function).
|
|
139
|
+
#### `parseFile` function
|
|
173
140
|
|
|
174
|
-
|
|
141
|
+
The `parseFile` function is intended for extracting metadata from audio files on the local filesystem in a Node.js environment.
|
|
142
|
+
It reads the specified file, parses its audio metadata, and returns a promise that resolves with this information.
|
|
175
143
|
|
|
144
|
+
##### Syntax
|
|
176
145
|
```ts
|
|
177
|
-
parseFile(filePath: string,
|
|
146
|
+
parseFile(filePath: string, options?: IOptions): Promise<IAudioMetadata>
|
|
178
147
|
```
|
|
179
148
|
|
|
180
|
-
|
|
149
|
+
##### Parameters
|
|
150
|
+
|
|
151
|
+
- `filePath`: `string`
|
|
152
|
+
|
|
153
|
+
The path to the media file from which metadata should be extracted.
|
|
154
|
+
This should be a valid path to an audio file on the local filesystem.
|
|
155
|
+
|
|
156
|
+
- `options`: [IOptions](#ioptions-interface) (optional)
|
|
157
|
+
|
|
158
|
+
An optional configuration object that allows customization of the parsing process.
|
|
159
|
+
These options can include whether to calculate the file's duration, skip embedded cover art,
|
|
160
|
+
or other parsing behaviors.
|
|
161
|
+
|
|
162
|
+
##### Returns
|
|
163
|
+
|
|
164
|
+
- `Promise<IAudioMetadata>`:
|
|
165
|
+
|
|
166
|
+
A promise that resolves to an IAudioMetadata object containing metadata about the audio file.
|
|
167
|
+
The metadata includes details such as the file format, codec, duration, bit rate, and any embedded tags like album, artist, or track information.
|
|
168
|
+
|
|
169
|
+
##### Usage Notes
|
|
170
|
+
|
|
171
|
+
- This function is **Node.js-only** and relies on Node.js-specific APIs to access the filesystem.
|
|
172
|
+
|
|
173
|
+
- For browser environments, consider using the [parseBlob](#parseblob-function) to parse [File object](https://developer.mozilla.org/en-US/docs/Web/API/File) objects.
|
|
174
|
+
|
|
175
|
+
##### Example:
|
|
176
|
+
|
|
177
|
+
The following example demonstrates how to use the parseFile function to read metadata from an audio file:
|
|
181
178
|
```js
|
|
182
179
|
import { parseFile } from 'music-metadata';
|
|
183
180
|
import { inspect } from 'util';
|
|
184
181
|
|
|
185
182
|
(async () => {
|
|
186
183
|
try {
|
|
187
|
-
const
|
|
184
|
+
const filePath = '../music-metadata/test/samples/MusicBrainz - Beth Hart - Sinner\'s Prayer [id3v2.3].V2.mp3';
|
|
185
|
+
const metadata = await parseFile(filePath);
|
|
186
|
+
|
|
187
|
+
// Output the parsed metadata to the console in a readable format
|
|
188
188
|
console.log(inspect(metadata, { showHidden: false, depth: null }));
|
|
189
189
|
} catch (error) {
|
|
190
|
-
console.error(error.message);
|
|
190
|
+
console.error('Error parsing metadata:', error.message);
|
|
191
191
|
}
|
|
192
192
|
})();
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
#### parseStream function
|
|
196
|
-
|
|
197
|
-
_Only available using a Node.js JavaScript engines._
|
|
195
|
+
#### `parseStream` function
|
|
198
196
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
It is recommended to provide the corresponding [MIME-type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types).
|
|
202
|
-
An extension (e.g.: `.mp3`), filename or path will also work.
|
|
203
|
-
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.
|
|
197
|
+
The parseStream function is used to parse metadata from an audio track provided as a Node.js [`Readable`](https://nodejs.org/api/stream.html#class-streamreadable) stream.
|
|
198
|
+
This is particularly useful for processing audio data that is being streamed or piped from another source, such as a web server or file system.
|
|
204
199
|
|
|
200
|
+
##### Syntax:
|
|
205
201
|
```ts
|
|
206
|
-
parseStream(stream:
|
|
202
|
+
parseStream(stream: Readable, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>
|
|
207
203
|
```
|
|
208
204
|
|
|
209
|
-
|
|
205
|
+
##### Parameters:
|
|
206
|
+
|
|
207
|
+
- `stream`: `Readable`:
|
|
208
|
+
|
|
209
|
+
The Node.js [Readable](https://nodejs.org/api/stream.html#class-streamreadable) stream from which the audio data is read.
|
|
210
|
+
This stream should provide the raw audio data to be analyzed.
|
|
211
|
+
|
|
212
|
+
- `fileInfo`: `IFileInfo` (optional)
|
|
213
|
+
|
|
214
|
+
An object containing file-related information or a string representing the MIME-type of the audio stream.
|
|
215
|
+
The fileInfo parameter can help the parser to correctly identify the audio format and may include:
|
|
216
|
+
|
|
217
|
+
- `mimeType`: A string representing the [MIME-type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) (e.g., `audio/mpeg`).
|
|
218
|
+
|
|
219
|
+
If provided, it is assumed the streamed file content is to be the MIME-type.
|
|
220
|
+
If not provided, the parser will attempt to determine the format based on the content of the stream.
|
|
221
|
+
|
|
222
|
+
- `size`: The total size of the audio stream in bytes (useful for streams with a known length).
|
|
223
|
+
|
|
224
|
+
- `path`: A string representing the file path or filename, which can also assist in determining the format.
|
|
225
|
+
|
|
226
|
+
- `options`: `IOptions` (optional)
|
|
227
|
+
|
|
228
|
+
An optional object containing additional parsing options.
|
|
229
|
+
These options allow you to customize the parsing process,
|
|
230
|
+
such as whether to calculate the duration or skip cover art extraction.
|
|
231
|
+
|
|
232
|
+
##### Returns
|
|
233
|
+
|
|
234
|
+
- `Promise<IAudioMetadata>`:
|
|
235
|
+
|
|
236
|
+
A promise that resolves to an `IAudioMetadata` object containing detailed metadata about the audio stream.
|
|
237
|
+
This metadata includes information about the format, codec, duration, bitrate, and any embedded tags such as artist, album, or track information.
|
|
238
|
+
|
|
239
|
+
##### Usage Notes
|
|
240
|
+
- This function is only available in Node.js environments, as it relies on the [Node.js stream API](https://nodejs.org/api/stream.html).
|
|
241
|
+
|
|
242
|
+
##### Example:
|
|
243
|
+
|
|
244
|
+
The following example demonstrates how to use the `parseStream` function to read metadata from an audio stream:
|
|
210
245
|
```js
|
|
211
246
|
import { parseStream } from 'music-metadata';
|
|
247
|
+
import { createReadStream } from 'fs';
|
|
212
248
|
|
|
213
249
|
(async () => {
|
|
214
250
|
try {
|
|
215
|
-
|
|
251
|
+
// Create a readable stream from a file
|
|
252
|
+
const audioStream = createReadStream('path/to/audio/file.mp3');
|
|
253
|
+
|
|
254
|
+
// Parse the metadata from the stream
|
|
255
|
+
const metadata = await parseStream(audioStream, { mimeType: 'audio/mpeg'});
|
|
256
|
+
|
|
257
|
+
// Log the parsed metadata
|
|
216
258
|
console.log(metadata);
|
|
217
259
|
} catch (error) {
|
|
218
|
-
console.error(error.message);
|
|
260
|
+
console.error('Error parsing metadata:', error.message);
|
|
219
261
|
}
|
|
220
262
|
})();
|
|
263
|
+
|
|
221
264
|
```
|
|
222
265
|
|
|
223
|
-
|
|
266
|
+
### Cross-platform functions
|
|
267
|
+
These functions are designed to be cross-platform,
|
|
268
|
+
meaning it can be used in both Node.js and web browsers.
|
|
269
|
+
|
|
270
|
+
#### `parseWebStream` function
|
|
224
271
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
An extension (e.g.: `.mp3`), filename or path will also work.
|
|
229
|
-
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.
|
|
272
|
+
The parseWebStream function is used to extract metadata from an audio track provided as a web-compatible ReadableStream.
|
|
273
|
+
This function is ideal for applications running in web environments, such as browsers,
|
|
274
|
+
where audio data is streamed over the network or read from other web-based sources.
|
|
230
275
|
|
|
276
|
+
|
|
277
|
+
##### Syntax
|
|
231
278
|
```ts
|
|
232
|
-
parseWebStream(
|
|
279
|
+
parseWebStream(webStream: ReadableStream<Uint8Array>, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>
|
|
233
280
|
```
|
|
234
281
|
|
|
235
|
-
|
|
282
|
+
##### Parameters
|
|
283
|
+
|
|
284
|
+
- `webStream`: `ReadableStream<Uint8Array>`
|
|
285
|
+
|
|
286
|
+
A [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream) that provides the audio data to be parsed.
|
|
287
|
+
This stream should emit Uint8Array chunks, representing the raw audio data.
|
|
288
|
+
|
|
289
|
+
- `fileInfo`: `IFileInfo` (optional)
|
|
290
|
+
|
|
291
|
+
An object containing file-related information or a string representing the MIME-type of the audio stream.
|
|
292
|
+
The fileInfo parameter can help the parser to correctly identify the audio format and may include:
|
|
293
|
+
|
|
294
|
+
- `mimeType`: A string representing the [MIME-type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) (e.g., `audio/mpeg`).
|
|
236
295
|
|
|
237
|
-
|
|
296
|
+
If provided, it is assumed the streamed file content is to be the MIME-type.
|
|
297
|
+
If not provided, the parser will attempt to determine the format based on the content of the stream.
|
|
238
298
|
|
|
239
|
-
|
|
299
|
+
- `size`: The total size of the audio stream in bytes (useful for streams with a known length).
|
|
300
|
+
|
|
301
|
+
- `path`: A string representing the file path or filename, which can also assist in determining the format.
|
|
302
|
+
|
|
303
|
+
- `options`: `IOptions` (optional)
|
|
304
|
+
|
|
305
|
+
An optional object containing additional parsing options.
|
|
306
|
+
These options allow you to customize the parsing process,
|
|
307
|
+
such as whether to calculate the duration or skip cover art extraction.
|
|
308
|
+
|
|
309
|
+
##### Returns
|
|
310
|
+
|
|
311
|
+
- `Promise<IAudioMetadata>`:
|
|
312
|
+
|
|
313
|
+
A promise that resolves to an `IAudioMetadata` object containing detailed metadata about the audio stream.
|
|
314
|
+
This metadata includes information about the format, codec, duration, bitrate, and any embedded tags such as artist, album, or track information.
|
|
315
|
+
|
|
316
|
+
##### Example
|
|
317
|
+
Here’s an example of how to use the `parseWebStream` function to extract metadata from an audio stream in a web application:
|
|
240
318
|
|
|
241
319
|
```js
|
|
242
|
-
|
|
320
|
+
import { parseWebStream } from 'music-metadata';
|
|
243
321
|
|
|
244
|
-
|
|
322
|
+
(async () => {
|
|
323
|
+
try {
|
|
324
|
+
// Assuming you have a ReadableStream of an audio file
|
|
325
|
+
const response = await fetch('https://example.com/path/to/audio/file.mp3');
|
|
326
|
+
const webStream = response.body;
|
|
327
|
+
|
|
328
|
+
// Parse the metadata from the web stream
|
|
329
|
+
const metadata = await parseWebStream(webStream, 'audio/mpeg');
|
|
245
330
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
331
|
+
// Log the parsed metadata
|
|
332
|
+
console.log(metadata);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.error('Error parsing metadata:', error.message);
|
|
335
|
+
}
|
|
336
|
+
})();
|
|
249
337
|
```
|
|
250
|
-
|
|
338
|
+
|
|
339
|
+
The example uses the [`fetch` API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to retrieve an audio file from a URL.
|
|
340
|
+
The `response.body` provides a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream) that is then passed to `parseWebStream`.
|
|
341
|
+
|
|
342
|
+
#### `parseBlob` function
|
|
343
|
+
|
|
344
|
+
Parses metadata from an audio file represented as a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob).
|
|
345
|
+
This function is suitable for use in environments that support the ReadableStreamBYOBReader, which is **available in Node.js 20** and above.
|
|
346
|
+
|
|
347
|
+
##### Syntax
|
|
348
|
+
```ts
|
|
349
|
+
parseBlob(blob: Blob, options?: IOptions = {}): Promise<IAudioMetadata>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
##### Parameters
|
|
353
|
+
|
|
354
|
+
- `blob`: [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
|
|
355
|
+
|
|
356
|
+
The Blob object containing the audio data to be parsed.
|
|
357
|
+
This can be a file or any binary data. If the Blob is an instance of File, its name will be used as the file path in the metadata.
|
|
358
|
+
|
|
359
|
+
- `options`: [IOptions](#ioptions-interface) (optional)
|
|
360
|
+
|
|
361
|
+
An optional configuration object that specifies parsing options.
|
|
362
|
+
|
|
363
|
+
##### Returns
|
|
364
|
+
|
|
365
|
+
- `Promise<IAudioMetadata>`:
|
|
366
|
+
|
|
367
|
+
A promise that resolves to the metadata of the audio file.
|
|
368
|
+
|
|
369
|
+
##### Example
|
|
370
|
+
|
|
251
371
|
```js
|
|
252
|
-
|
|
253
|
-
let blob; // File or Blob
|
|
372
|
+
import { parseBlob } from 'music-metadata';
|
|
254
373
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
374
|
+
(async () => {
|
|
375
|
+
const fileInput = document.querySelector('input[type="file"]');
|
|
376
|
+
const file = fileInput.files[0];
|
|
377
|
+
|
|
378
|
+
try {
|
|
379
|
+
const metadata = await parseBlob(file);
|
|
380
|
+
console.log(metadata);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.error('Error parsing metadata:', error.message);
|
|
383
|
+
}
|
|
384
|
+
})();
|
|
258
385
|
```
|
|
259
386
|
|
|
260
|
-
#### parseBuffer function
|
|
387
|
+
#### `parseBuffer` function
|
|
261
388
|
|
|
262
|
-
|
|
389
|
+
Parses metadata from an audio file where the audio data is held in a [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) or [Buffer](https://nodejs.org/api/buffer.html).
|
|
390
|
+
This function is particularly useful when you already have audio data in memory.
|
|
263
391
|
|
|
392
|
+
##### Syntax
|
|
264
393
|
```ts
|
|
265
394
|
parseBuffer(buffer: Uint8Array, fileInfo?: IFileInfo | string, opts?: IOptions = {}): Promise<IAudioMetadata>
|
|
266
395
|
```
|
|
267
396
|
|
|
268
|
-
|
|
397
|
+
##### Parameters
|
|
398
|
+
- `uint8Array`: [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array)
|
|
399
|
+
|
|
400
|
+
A [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) containing the audio data to be parsed.
|
|
401
|
+
|
|
402
|
+
- `fileInfo`: `IFileInfo` | `string` (optional)
|
|
403
|
+
|
|
404
|
+
An object containing file information such as mimeType and size.
|
|
405
|
+
Alternatively, you can pass a MIME-type string directly.
|
|
406
|
+
This helps the parser understand the format of the audio data.
|
|
407
|
+
|
|
408
|
+
- `options`: [IOptions](#ioptions-interface) (optional)
|
|
409
|
+
|
|
410
|
+
An optional configuration object that specifies parsing options.
|
|
411
|
+
|
|
412
|
+
##### Returns
|
|
413
|
+
- `Promise<IAudioMetadata>`:
|
|
414
|
+
|
|
415
|
+
A promise that resolves to the metadata of the audio file.
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
##### Example
|
|
419
|
+
|
|
269
420
|
```js
|
|
270
421
|
import { parseBuffer } from 'music-metadata';
|
|
422
|
+
import fs from 'fs';
|
|
271
423
|
|
|
272
424
|
(async () => {
|
|
425
|
+
const buffer = fs.readFileSync('path/to/audio/file.mp3');
|
|
426
|
+
|
|
273
427
|
try {
|
|
274
|
-
const metadata = await parseBuffer(
|
|
428
|
+
const metadata = await parseBuffer(buffer, { mimeType: 'audio/mpeg' });
|
|
275
429
|
console.log(metadata);
|
|
276
430
|
} catch (error) {
|
|
277
|
-
console.error(error.message);
|
|
431
|
+
console.error('Error parsing metadata:', error.message);
|
|
278
432
|
}
|
|
279
433
|
})();
|
|
280
434
|
```
|
|
281
435
|
|
|
282
|
-
#### parseFromTokenizer function
|
|
283
|
-
|
|
436
|
+
#### `parseFromTokenizer` function
|
|
437
|
+
Parses metadata from an audio source that implements the [strtok3](https://github.com/Borewit/strtok3) ITokenizer interface.
|
|
438
|
+
This is a low-level function that provides flexibility for advanced use cases,
|
|
439
|
+
such as parsing metadata from streaming audio or custom data sources.
|
|
284
440
|
|
|
285
441
|
This also enables special read modules like:
|
|
286
442
|
- [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).
|
|
287
443
|
|
|
288
|
-
|
|
444
|
+
##### Syntax
|
|
445
|
+
```ts
|
|
446
|
+
parseFromTokenizer(tokenizer: ITokenizer, options?: IOptions): Promise<IAudioMetadata>
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
##### Parameters
|
|
450
|
+
- `tokenizer: ITokenizer`
|
|
451
|
+
|
|
452
|
+
An instance of an ITokenizer that provides access to the audio data.
|
|
453
|
+
The tokenizer abstracts the reading process, enabling support for various types of sources, including streams, buffers, or custom data readers.
|
|
454
|
+
|
|
455
|
+
- `options`: [IOptions](#ioptions-interface) (optional)
|
|
456
|
+
|
|
457
|
+
An optional configuration object that specifies parsing options.
|
|
458
|
+
|
|
459
|
+
##### Returns
|
|
460
|
+
- `Promise<IAudioMetadata>`:
|
|
461
|
+
|
|
462
|
+
A promise that resolves to the metadata of the audio source, including information like the title, artist, album, and more.
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
##### Example
|
|
466
|
+
````js
|
|
467
|
+
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
|
|
468
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
469
|
+
import { makeTokenizer } from '@tokenizer/s3';
|
|
470
|
+
import { parseFromTokenizer as mmParseFromTokenizer } from 'music-metadata';
|
|
471
|
+
|
|
472
|
+
// Configure the S3 client
|
|
473
|
+
const s3 = new S3Client({
|
|
474
|
+
region: 'eu-west-2',
|
|
475
|
+
credentials: fromNodeProviderChain(),
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// Helper function to create a tokenizer for S3 objects
|
|
479
|
+
async function makeS3TestDataTokenizer(key, options) {
|
|
480
|
+
return await makeTokenizer(s3, {
|
|
481
|
+
Bucket: 'music-metadata',
|
|
482
|
+
Key: key,
|
|
483
|
+
}, options);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Function to read and log metadata from an S3 object
|
|
487
|
+
async function readMetadata() {
|
|
488
|
+
try {
|
|
489
|
+
// Create a tokenizer for the specified S3 object
|
|
490
|
+
const tokenizer = await makeS3TestDataTokenizer('path/to/audio/file.mp3', { disableChunked: false });
|
|
491
|
+
|
|
492
|
+
// Parse the metadata from the tokenizer
|
|
493
|
+
const metadata = await mmParseFromTokenizer(tokenizer);
|
|
494
|
+
|
|
495
|
+
// Log the retrieved metadata
|
|
496
|
+
console.log(metadata);
|
|
497
|
+
} catch (error) {
|
|
498
|
+
console.error('Error parsing metadata:', error.message);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Execute the metadata reading function
|
|
503
|
+
readMetadata();
|
|
504
|
+
````
|
|
505
|
+
##### Additional Resources
|
|
506
|
+
- [strtok3](https://github.com/Borewit/strtok3) - Learn more about the `ITokenizer` interface and how to implement it for various use cases.
|
|
507
|
+
- [AWS SDK for JavaScript](https://aws.amazon.com/sdk-for-javascript/) - Documentation on using the AWS SDK to interact with S3 and other AWS services.
|
|
508
|
+
- [@tokenizer/s3](https://github.com/Borewit/tokenizer-s3) - Example of `ITokenizer` implementation.
|
|
509
|
+
|
|
510
|
+
### Handling Parse Errors
|
|
511
|
+
|
|
512
|
+
`music-metadata` provides a robust and extensible error handling system with custom error classes that inherit from the standard JavaScript `Error`.
|
|
513
|
+
All possible parsing errors are part of a union type `UnionOfParseErrors`, ensuring that every error scenario is accounted for in your code.
|
|
514
|
+
|
|
515
|
+
#### Union of Parse Errors
|
|
516
|
+
|
|
517
|
+
All parsing errors extend from the base class `ParseError` and are included in the `UnionOfParseErrors` type:
|
|
518
|
+
```ts
|
|
519
|
+
export type UnionOfParseErrors =
|
|
520
|
+
| CouldNotDetermineFileTypeError
|
|
521
|
+
| UnsupportedFileTypeError
|
|
522
|
+
| UnexpectedFileContentError
|
|
523
|
+
| FieldDecodingError
|
|
524
|
+
| InternalParserError;
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### Error Types
|
|
528
|
+
|
|
529
|
+
- `CouldNotDetermineFileTypeError`: Raised when the file type cannot be determined.
|
|
530
|
+
- `UnsupportedFileTypeError`: Raised when an unsupported file type is encountered.
|
|
531
|
+
- `UnexpectedFileContentError`: Raised when the file content does not match the expected format.
|
|
532
|
+
- `FieldDecodingError`: Raised when a specific field in the file cannot be decoded.
|
|
533
|
+
- `InternalParserError`: Raised for internal parser errors.
|
|
534
|
+
|
|
535
|
+
### Other functions
|
|
536
|
+
|
|
537
|
+
#### `orderTags` function
|
|
289
538
|
|
|
290
539
|
Utility to Converts the native tags to a dictionary index on the tag identifier
|
|
291
540
|
|
|
@@ -308,14 +557,14 @@ import { inspect } from 'util';
|
|
|
308
557
|
})();
|
|
309
558
|
```
|
|
310
559
|
|
|
311
|
-
#### ratingToStars function
|
|
560
|
+
#### `ratingToStars` function
|
|
312
561
|
|
|
313
562
|
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.
|
|
314
563
|
|
|
315
564
|
```ts
|
|
316
565
|
ratingToStars(rating: number): number
|
|
317
566
|
```
|
|
318
|
-
#### selectCover function
|
|
567
|
+
#### `selectCover` function
|
|
319
568
|
|
|
320
569
|
Select cover image based on image type field, otherwise the first picture in file.
|
|
321
570
|
|
|
@@ -333,21 +582,33 @@ import { parseFile, selectCover } from 'music-metadata';
|
|
|
333
582
|
)();
|
|
334
583
|
```
|
|
335
584
|
|
|
336
|
-
###
|
|
337
|
-
- `duration`: default: `false
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
- `mkvUseIndex` default: `false`, if set to `true`, in Matroska based files, use the _SeekHead_ element index to skip _segment/cluster_ elements..
|
|
342
|
-
_experimental functionality_
|
|
343
|
-
Can have a significant performance impact if enabled.
|
|
344
|
-
Possible side effect can be that certain metadata maybe skipped, depending on the index.
|
|
345
|
-
If there is no _SeekHead_ element present in the Matroska file, this flag has no effect.
|
|
585
|
+
### `IOptions` Interface
|
|
586
|
+
- `duration`: `boolean` (default: `false`)
|
|
587
|
+
|
|
588
|
+
If set to `true`, the parser will analyze the entire media file, if necessary, to determine its duration.
|
|
589
|
+
This option ensures accurate duration calculation but may increase processing time for large files.
|
|
346
590
|
|
|
347
|
-
|
|
348
|
-
To enforce parsing the entire file if needed you should set `duration` to `true`.
|
|
591
|
+
- `observer`: `(update: MetadataEvent) => void;`:
|
|
349
592
|
|
|
350
|
-
|
|
593
|
+
A callback function that is invoked whenever there is an update to the common (generic) tag or format properties during parsing.
|
|
594
|
+
This allows for real-time updates on metadata changes.
|
|
595
|
+
|
|
596
|
+
- `skipCovers`: `boolean` (default: `false`)
|
|
597
|
+
|
|
598
|
+
If set to `true`, the parser will skip the extraction of embedded cover art (images) from the media file.
|
|
599
|
+
This can be useful to avoid processing unnecessary data if cover images are not required.
|
|
600
|
+
|
|
601
|
+
- `mkvUseIndex`: `boolean` (default: `false`)
|
|
602
|
+
|
|
603
|
+
If set to true, the parser will use the SeekHead element index to skip segment/cluster elements in Matroska-based files. This is an experimental feature and can significantly impact performance. It may also result in some metadata being skipped if it is not indexed.
|
|
604
|
+
If the SeekHead element is absent in the Matroska file, this flag has no effect.
|
|
605
|
+
|
|
606
|
+
> [!NOTE]
|
|
607
|
+
> - The `duration` option is typically included in most cases, but setting it to true ensures that the entire file is parsed if necessary to get an accurate duration.
|
|
608
|
+
> - Using `mkvUseIndex` can improve performance in Matroska files, but be aware of potential side effects, such as missing metadata due to skipped elements.
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
### `IAudioMetadata` interface
|
|
351
612
|
|
|
352
613
|
If the returned promise resolves, the metadata (TypeScript `IAudioMetadata` interface) contains:
|
|
353
614
|
- [`metadata.format`](#metadataformat) Audio format information
|
|
@@ -471,6 +732,59 @@ import {uint8ArrayToBase64} from 'uint8array-extras';
|
|
|
471
732
|
img.src = `data:${picture.format};base64,${uint8ArrayToBase64(picture.data)}`;
|
|
472
733
|
```
|
|
473
734
|
|
|
735
|
+
## Dependencies
|
|
736
|
+
|
|
737
|
+
Dependency diagram:
|
|
738
|
+
```mermaid
|
|
739
|
+
graph TD;
|
|
740
|
+
MMN("music-metadata (Node.js entry point)")-->MMP
|
|
741
|
+
MMN-->FTN
|
|
742
|
+
MMP("music-metadata (primary entry point)")-->S(strtok3)
|
|
743
|
+
MMP-->TY(token-types)
|
|
744
|
+
MMP-->FTP
|
|
745
|
+
MMP-->UAE
|
|
746
|
+
FTN("file-type (Node.js entry point)")-->FTP
|
|
747
|
+
FTP("file-type (primary entry point)")-->S
|
|
748
|
+
S(strtok3)-->P(peek-readable)
|
|
749
|
+
S(strtok3)-->TO("@tokenizer/token")
|
|
750
|
+
TY(token-types)-->TO
|
|
751
|
+
TY-->IE("ieee754")
|
|
752
|
+
FTP-->TY
|
|
753
|
+
NS("node:stream")
|
|
754
|
+
FTN-->NS
|
|
755
|
+
FTP-->UAE(uint8array-extras)
|
|
756
|
+
style NS fill:#F88,stroke:#A44
|
|
757
|
+
style IE fill:#CCC,stroke:#888
|
|
758
|
+
style FTN fill:#FAA,stroke:#A44
|
|
759
|
+
style MMN fill:#FAA,stroke:#A44
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
Dependency list:
|
|
763
|
+
- [tokenizer-token](https://github.com/Borewit/tokenizer-token)
|
|
764
|
+
- [strtok3](https://github.com/Borewit/strtok3)
|
|
765
|
+
- [token-types](https://github.com/Borewit/token-types)
|
|
766
|
+
- [file-type](https://github.com/sindresorhus/file-type)
|
|
767
|
+
- [@tokenizer-token](https://github.com/Borewit/tokenizer-token)
|
|
768
|
+
- [peek-readable](https://github.com/Borewit/peek-readable)
|
|
769
|
+
|
|
770
|
+
## CommonJS Backward compatibility
|
|
771
|
+
|
|
772
|
+
For legacy CommonJS projects needing to load the `music-metadata` ESM module, you can use the `loadMusicMetadata` function:
|
|
773
|
+
```js
|
|
774
|
+
const { loadMusicMetadata } = require('music-metadata');
|
|
775
|
+
|
|
776
|
+
(async () => {
|
|
777
|
+
// Dynamically loads the ESM module in a CommonJS project
|
|
778
|
+
const mm = await loadMusicMetadata();
|
|
779
|
+
|
|
780
|
+
const metadata = await mm.parseFile('/path/to/your/file');
|
|
781
|
+
})();
|
|
782
|
+
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
> [!NOTE]
|
|
786
|
+
> The `loadMusicMetadata` function is experimental.
|
|
787
|
+
|
|
474
788
|
## Frequently Asked Questions
|
|
475
789
|
|
|
476
790
|
1. How can I traverse (a long) list of files?
|
|
@@ -517,16 +831,11 @@ img.src = `data:${picture.format};base64,${uint8ArrayToBase64(picture.data)}`;
|
|
|
517
831
|
}
|
|
518
832
|
```
|
|
519
833
|
|
|
520
|
-
1. Use a specialized module to traverse files
|
|
521
|
-
|
|
522
|
-
There are specialized modules to traversing (walking) files and directory,
|
|
523
|
-
like [walk](https://www.npmjs.com/package/walk).
|
|
524
|
-
|
|
525
834
|
## Licence
|
|
526
835
|
|
|
527
836
|
The MIT License (MIT)
|
|
528
837
|
|
|
529
|
-
Copyright ©
|
|
838
|
+
Copyright © 2024 Borewit
|
|
530
839
|
|
|
531
840
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
532
841
|
|