music-metadata 10.6.3 → 10.6.5
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 +36 -38
- package/lib/amr/AmrParser.js +10 -1
- package/lib/amr/AmrToken.d.ts +1 -2
- package/lib/core.js +8 -2
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -86,8 +86,6 @@ Following lyric formats are supported:
|
|
|
86
86
|
- [LRC](https://en.wikipedia.org/wiki/LRC_(file_format))
|
|
87
87
|
- Synchronized lyrics (SYLT)
|
|
88
88
|
- Unsynchronized lyrics (USULT)
|
|
89
|
-
[
|
|
90
|
-
It allows many tags to be]() accessed in audio format, and tag format independent way.
|
|
91
89
|
|
|
92
90
|
Support for [MusicBrainz](https://musicbrainz.org/) tags as written by [Picard](https://picard.musicbrainz.org/).
|
|
93
91
|
[ReplayGain](https://wiki.hydrogenaud.io/index.php?title=ReplayGain) tags are supported.
|
|
@@ -212,8 +210,8 @@ parseStream(stream: Readable, fileInfo?: IFileInfo | string, options?: IOptions)
|
|
|
212
210
|
|
|
213
211
|
- `stream`: `Readable`:
|
|
214
212
|
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
The Node.js [Readable](https://nodejs.org/api/stream.html#class-streamreadable) stream from which the audio data is read.
|
|
214
|
+
This stream should provide the raw audio data to be analyzed.
|
|
217
215
|
|
|
218
216
|
- `fileInfo`: `IFileInfo` (optional)
|
|
219
217
|
|
|
@@ -222,8 +220,8 @@ parseStream(stream: Readable, fileInfo?: IFileInfo | string, options?: IOptions)
|
|
|
222
220
|
|
|
223
221
|
- `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`).
|
|
224
222
|
|
|
225
|
-
|
|
226
|
-
|
|
223
|
+
If provided, it is assumed the streamed file content is to be the MIME-type.
|
|
224
|
+
If not provided, the parser will attempt to determine the format based on the content of the stream.
|
|
227
225
|
|
|
228
226
|
- `size`: The total size of the audio stream in bytes (useful for streams with a known length).
|
|
229
227
|
|
|
@@ -231,9 +229,9 @@ parseStream(stream: Readable, fileInfo?: IFileInfo | string, options?: IOptions)
|
|
|
231
229
|
|
|
232
230
|
- `options`: `IOptions` (optional)
|
|
233
231
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
232
|
+
An optional object containing additional parsing options.
|
|
233
|
+
These options allow you to customize the parsing process,
|
|
234
|
+
such as whether to calculate the duration or skip cover art extraction.
|
|
237
235
|
|
|
238
236
|
##### Returns
|
|
239
237
|
|
|
@@ -793,49 +791,49 @@ const { loadMusicMetadata } = require('music-metadata');
|
|
|
793
791
|
|
|
794
792
|
## Frequently Asked Questions
|
|
795
793
|
|
|
796
|
-
|
|
794
|
+
### How can I traverse (a long) list of files?
|
|
797
795
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
796
|
+
What is important that file parsing should be done in a sequential manner.
|
|
797
|
+
In a plain loop, due to the asynchronous character (like most JavaScript functions), it would cause all the files to run in parallel which is will cause your application to hang in no time.
|
|
798
|
+
There are multiple ways of achieving this:
|
|
801
799
|
|
|
802
|
-
|
|
800
|
+
1. Using recursion
|
|
803
801
|
|
|
804
|
-
|
|
805
|
-
|
|
802
|
+
```js
|
|
803
|
+
import { parseFile } from 'music-metadata';
|
|
806
804
|
|
|
807
|
-
|
|
805
|
+
function parseFiles(audioFiles) {
|
|
808
806
|
|
|
809
|
-
|
|
807
|
+
const audioFile = audioFiles.shift();
|
|
810
808
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
809
|
+
if (audioFile) {
|
|
810
|
+
return parseFile(audioFile).then(metadata => {
|
|
811
|
+
// Do great things with the metadata
|
|
812
|
+
return parseFiles(audioFiles); // process rest of the files AFTER we are finished
|
|
813
|
+
})
|
|
814
|
+
}
|
|
815
|
+
}
|
|
818
816
|
|
|
819
|
-
|
|
817
|
+
```
|
|
820
818
|
|
|
821
|
-
|
|
819
|
+
1. Use async/await
|
|
822
820
|
|
|
823
|
-
|
|
821
|
+
Use [async/await](https://javascript.info/async-await)
|
|
824
822
|
|
|
825
|
-
|
|
826
|
-
|
|
823
|
+
```js
|
|
824
|
+
import { parseFile } from 'music-metadata';
|
|
827
825
|
|
|
828
|
-
|
|
829
|
-
|
|
826
|
+
// it is required to declare the function 'async' to allow the use of await
|
|
827
|
+
async function parseFiles(audioFiles) {
|
|
830
828
|
|
|
831
|
-
|
|
829
|
+
for (const audioFile of audioFiles) {
|
|
832
830
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
}
|
|
831
|
+
// await will ensure the metadata parsing is completed before we move on to the next file
|
|
832
|
+
const metadata = await parseFile(audioFile);
|
|
833
|
+
// Do great things with the metadata
|
|
837
834
|
}
|
|
838
|
-
|
|
835
|
+
}
|
|
836
|
+
```
|
|
839
837
|
|
|
840
838
|
## Licence
|
|
841
839
|
|
package/lib/amr/AmrParser.js
CHANGED
|
@@ -2,6 +2,7 @@ import { BasicParser } from '../common/BasicParser.js';
|
|
|
2
2
|
import { AnsiStringType } from 'token-types';
|
|
3
3
|
import initDebug from 'debug';
|
|
4
4
|
import { FrameHeader } from './AmrToken.js';
|
|
5
|
+
import { EndOfStreamError } from 'strtok3';
|
|
5
6
|
const debug = initDebug('music-metadata:parser:AMR');
|
|
6
7
|
/**
|
|
7
8
|
* There are 8 varying levels of compression. First byte of the frame specifies CMR
|
|
@@ -27,8 +28,16 @@ export class AmrParser extends BasicParser {
|
|
|
27
28
|
let frames = 0;
|
|
28
29
|
const assumedFileLength = this.tokenizer.fileInfo?.size ?? Number.MAX_SAFE_INTEGER;
|
|
29
30
|
if (this.options.duration) {
|
|
31
|
+
let header;
|
|
30
32
|
while (this.tokenizer.position < assumedFileLength) {
|
|
31
|
-
|
|
33
|
+
try {
|
|
34
|
+
header = await this.tokenizer.readToken(FrameHeader);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof EndOfStreamError)
|
|
38
|
+
break;
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
32
41
|
/* first byte is rate mode. each rate mode has frame of given length. look it up. */
|
|
33
42
|
const size = m_block_size[header.frameType];
|
|
34
43
|
if (size > 0) {
|
package/lib/amr/AmrToken.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IGetToken } from 'strtok3';
|
|
2
|
-
interface IFrameHeader {
|
|
2
|
+
export interface IFrameHeader {
|
|
3
3
|
frameType: number;
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
@@ -8,4 +8,3 @@ interface IFrameHeader {
|
|
|
8
8
|
* ToDo
|
|
9
9
|
*/
|
|
10
10
|
export declare const FrameHeader: IGetToken<IFrameHeader>;
|
|
11
|
-
export {};
|
package/lib/core.js
CHANGED
|
@@ -28,8 +28,14 @@ export async function parseBlob(blob, options = {}) {
|
|
|
28
28
|
* @param fileInfo - File information object or MIME-type string
|
|
29
29
|
* @returns Metadata
|
|
30
30
|
*/
|
|
31
|
-
export function parseWebStream(webStream, fileInfo, options = {}) {
|
|
32
|
-
|
|
31
|
+
export async function parseWebStream(webStream, fileInfo, options = {}) {
|
|
32
|
+
const tokenizer = fromWebStream(webStream, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo });
|
|
33
|
+
try {
|
|
34
|
+
return await parseFromTokenizer(tokenizer, options);
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
await tokenizer.close();
|
|
38
|
+
}
|
|
33
39
|
}
|
|
34
40
|
/**
|
|
35
41
|
* Parse audio from memory
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "music-metadata",
|
|
3
3
|
"description": "Music metadata parser for Node.js, supporting virtual any audio and tag format.",
|
|
4
|
-
"version": "10.6.
|
|
4
|
+
"version": "10.6.5",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Borewit",
|
|
7
7
|
"url": "https://github.com/Borewit"
|
|
@@ -107,11 +107,11 @@
|
|
|
107
107
|
"dependencies": {
|
|
108
108
|
"@tokenizer/token": "^0.3.0",
|
|
109
109
|
"content-type": "^1.0.5",
|
|
110
|
-
"debug": "^4.
|
|
110
|
+
"debug": "^4.4.0",
|
|
111
111
|
"file-type": "^19.6.0",
|
|
112
112
|
"link": "^2.1.1",
|
|
113
113
|
"media-typer": "^1.1.0",
|
|
114
|
-
"strtok3": "^10.0.
|
|
114
|
+
"strtok3": "^10.0.1",
|
|
115
115
|
"token-types": "^6.0.0",
|
|
116
116
|
"uint8array-extras": "^1.4.0"
|
|
117
117
|
},
|
|
@@ -124,12 +124,12 @@
|
|
|
124
124
|
"@types/media-typer": "^1.1.3",
|
|
125
125
|
"@types/mocha": "^10.0.10",
|
|
126
126
|
"@types/node": "^22.10.1",
|
|
127
|
-
"c8": "^10.1.
|
|
127
|
+
"c8": "^10.1.3",
|
|
128
128
|
"chai": "^5.1.2",
|
|
129
129
|
"chai-as-promised": "^8.0.1",
|
|
130
130
|
"del-cli": "^6.0.0",
|
|
131
|
-
"mime": "^4.0.
|
|
132
|
-
"mocha": "^
|
|
131
|
+
"mime": "^4.0.6",
|
|
132
|
+
"mocha": "^11.0.1",
|
|
133
133
|
"remark-cli": "^12.0.1",
|
|
134
134
|
"remark-preset-lint-consistent": "^6.0.0",
|
|
135
135
|
"ts-node": "^10.9.2",
|