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.
- package/README.md +152 -132
- package/lib/ParserFactory.d.ts +1 -1
- package/lib/ParserFactory.js +1 -2
- package/lib/aiff/AiffParser.js +3 -4
- package/lib/aiff/AiffToken.d.ts +2 -4
- package/lib/aiff/AiffToken.js +7 -7
- package/lib/apev2/APEv2Parser.d.ts +1 -1
- package/lib/apev2/APEv2Parser.js +10 -12
- package/lib/apev2/APEv2Token.d.ts +1 -1
- package/lib/asf/AsfObject.d.ts +15 -17
- package/lib/asf/AsfObject.js +51 -45
- package/lib/asf/AsfParser.js +6 -8
- package/lib/asf/AsfUtil.d.ts +1 -3
- package/lib/asf/AsfUtil.js +4 -5
- package/lib/asf/GUID.d.ts +4 -5
- package/lib/asf/GUID.js +14 -11
- package/lib/common/BasicParser.d.ts +1 -1
- package/lib/common/FourCC.d.ts +1 -1
- package/lib/common/FourCC.js +5 -3
- package/lib/common/MetadataCollector.d.ts +3 -3
- package/lib/common/MetadataCollector.js +7 -8
- package/lib/common/RandomFileReader.d.ts +0 -1
- package/lib/common/Util.d.ts +1 -1
- package/lib/common/Util.js +4 -3
- package/lib/core.d.ts +16 -8
- package/lib/core.js +19 -5
- package/lib/dsdiff/DsdiffParser.js +1 -1
- package/lib/dsdiff/DsdiffToken.d.ts +1 -1
- package/lib/dsf/DsfChunk.d.ts +1 -1
- package/lib/flac/FlacParser.d.ts +1 -1
- package/lib/flac/FlacParser.js +6 -4
- package/lib/id3v1/ID3v1Parser.js +6 -6
- package/lib/id3v2/AbstractID3Parser.d.ts +1 -1
- package/lib/id3v2/AbstractID3Parser.js +1 -1
- package/lib/id3v2/FrameParser.js +3 -3
- package/lib/id3v2/ID3v24TagMapper.d.ts +2 -3
- package/lib/id3v2/ID3v24TagMapper.js +4 -4
- package/lib/id3v2/ID3v2Parser.d.ts +1 -1
- package/lib/id3v2/ID3v2Parser.js +10 -17
- package/lib/id3v2/ID3v2Token.d.ts +1 -1
- package/lib/id3v2/ID3v2Token.js +2 -2
- package/lib/iff/index.d.ts +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +1 -1
- package/lib/lyrics3/Lyrics3.js +1 -1
- package/lib/matroska/MatroskaParser.d.ts +1 -1
- package/lib/matroska/MatroskaParser.js +16 -20
- package/lib/matroska/types.d.ts +0 -1
- package/lib/mp4/Atom.d.ts +1 -1
- package/lib/mp4/AtomToken.d.ts +2 -3
- package/lib/mp4/AtomToken.js +2 -2
- package/lib/mp4/MP4Parser.js +20 -19
- package/lib/mpeg/ExtendedLameHeader.d.ts +1 -1
- package/lib/mpeg/MpegParser.js +1 -1
- package/lib/mpeg/ReplayGainDataFormat.d.ts +1 -1
- package/lib/mpeg/XingTag.d.ts +1 -2
- package/lib/musepack/index.js +1 -1
- package/lib/musepack/sv7/BitReader.d.ts +1 -1
- package/lib/musepack/sv7/StreamVersion7.d.ts +1 -1
- package/lib/musepack/sv7/StreamVersion7.js +1 -1
- package/lib/musepack/sv8/StreamVersion8.d.ts +1 -1
- package/lib/musepack/sv8/StreamVersion8.js +1 -1
- package/lib/ogg/Ogg.d.ts +2 -2
- package/lib/ogg/OggParser.d.ts +1 -1
- package/lib/ogg/OggParser.js +5 -5
- package/lib/ogg/opus/Opus.d.ts +1 -1
- package/lib/ogg/opus/Opus.js +6 -6
- package/lib/ogg/opus/OpusParser.d.ts +2 -3
- package/lib/ogg/opus/OpusParser.js +2 -2
- package/lib/ogg/speex/Speex.d.ts +1 -1
- package/lib/ogg/speex/Speex.js +13 -13
- package/lib/ogg/speex/SpeexParser.d.ts +1 -2
- package/lib/ogg/theora/Theora.d.ts +1 -1
- package/lib/ogg/theora/Theora.js +6 -6
- package/lib/ogg/theora/TheoraParser.d.ts +4 -5
- package/lib/ogg/theora/TheoraParser.js +4 -4
- package/lib/ogg/vorbis/Vorbis.d.ts +3 -4
- package/lib/ogg/vorbis/Vorbis.js +11 -12
- package/lib/ogg/vorbis/VorbisDecoder.js +1 -1
- package/lib/ogg/vorbis/VorbisParser.d.ts +6 -7
- package/lib/ogg/vorbis/VorbisParser.js +11 -11
- package/lib/riff/RiffChunk.d.ts +1 -1
- package/lib/riff/RiffChunk.js +2 -2
- package/lib/type.d.ts +9 -11
- package/lib/wav/BwfChunk.d.ts +1 -1
- package/lib/wav/WaveChunk.d.ts +2 -3
- package/lib/wav/WaveChunk.js +8 -7
- package/lib/wav/WaveParser.js +2 -2
- package/lib/wavpack/WavPackParser.js +1 -1
- package/lib/wavpack/WavPackToken.d.ts +1 -1
- package/package.json +26 -25
package/lib/common/Util.js
CHANGED
|
@@ -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 === '
|
|
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 === '
|
|
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
|
|
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
|
-
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
export
|
|
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
|
|
8
|
-
*
|
|
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
|
|
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
|
|
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
|
|
9
|
-
*
|
|
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
|
|
15
|
-
return parseFromTokenizer(strtok3.
|
|
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
|
|
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';
|
package/lib/dsf/DsfChunk.d.ts
CHANGED
package/lib/flac/FlacParser.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ITokenizer } from 'strtok3
|
|
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';
|
package/lib/flac/FlacParser.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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) {
|
package/lib/id3v1/ID3v1Parser.js
CHANGED
|
@@ -68,7 +68,7 @@ const Iid3v1Token = {
|
|
|
68
68
|
};
|
|
69
69
|
class Id3v1StringType extends StringType {
|
|
70
70
|
constructor(len) {
|
|
71
|
-
super(len, '
|
|
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('
|
|
126
|
+
return tag.toString('latin1') === 'TAG';
|
|
127
127
|
}
|
|
128
128
|
return false;
|
|
129
129
|
}
|
package/lib/id3v2/FrameParser.js
CHANGED
|
@@ -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 =
|
|
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 === '
|
|
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 === '
|
|
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
|
|
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 =
|
|
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
|
|
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
|
}
|
package/lib/id3v2/ID3v2Parser.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
};
|
package/lib/id3v2/ID3v2Token.js
CHANGED
|
@@ -91,9 +91,9 @@ export const TextEncodingToken = {
|
|
|
91
91
|
case 0x00:
|
|
92
92
|
return { encoding: 'latin1' }; // binary
|
|
93
93
|
case 0x01:
|
|
94
|
-
return { encoding: '
|
|
94
|
+
return { encoding: 'utf-16le', bom: true };
|
|
95
95
|
case 0x02:
|
|
96
|
-
return { encoding: '
|
|
96
|
+
return { encoding: 'utf-16le', bom: false };
|
|
97
97
|
case 0x03:
|
|
98
98
|
return { encoding: 'utf8', bom: false };
|
|
99
99
|
default:
|
package/lib/iff/index.d.ts
CHANGED
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
|
package/lib/lyrics3/Lyrics3.js
CHANGED
|
@@ -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('
|
|
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;
|
|
@@ -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.
|
|
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.
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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(/\
|
|
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
|
}
|
package/lib/matroska/types.d.ts
CHANGED
package/lib/mp4/Atom.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as AtomToken from './AtomToken.js';
|
|
2
|
-
import { ITokenizer } from 'strtok3
|
|
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;
|
package/lib/mp4/AtomToken.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
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:
|
|
185
|
+
value: Uint8Array;
|
|
187
186
|
}
|
|
188
187
|
/**
|
|
189
188
|
* Data Atom Structure
|
package/lib/mp4/AtomToken.js
CHANGED
|
@@ -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, '
|
|
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:
|
|
153
|
+
value: new Token.Uint8ArrayType(this.len - 8).get(buf, off + 8)
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
156
|
}
|