music-metadata 10.0.1 → 10.2.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/LICENSE.txt +9 -9
- package/README.md +535 -520
- package/lib/ParserFactory.d.ts +20 -28
- package/lib/ParserFactory.js +204 -207
- package/lib/aiff/AiffParser.js +20 -19
- package/lib/aiff/AiffToken.d.ts +14 -2
- package/lib/aiff/AiffToken.js +12 -0
- package/lib/apev2/APEv2Parser.d.ts +4 -4
- package/lib/apev2/APEv2Parser.js +12 -10
- package/lib/apev2/APEv2Token.d.ts +2 -4
- package/lib/apev2/APEv2Token.js +0 -3
- package/lib/asf/AsfObject.d.ts +7 -16
- package/lib/asf/AsfObject.js +8 -34
- package/lib/asf/AsfParser.js +17 -10
- package/lib/asf/AsfTagMapper.d.ts +1 -1
- package/lib/asf/AsfTagMapper.js +3 -2
- package/lib/asf/AsfUtil.d.ts +3 -11
- package/lib/asf/AsfUtil.js +29 -30
- package/lib/asf/GUID.js +6 -9
- package/lib/common/BasicParser.d.ts +4 -4
- package/lib/common/BasicParser.js +6 -0
- package/lib/common/CaseInsensitiveTagMap.d.ts +1 -1
- package/lib/common/CombinedTagMapper.d.ts +5 -5
- package/lib/common/CombinedTagMapper.js +1 -1
- package/lib/common/FourCC.d.ts +1 -1
- package/lib/common/GenericTagMapper.d.ts +8 -8
- package/lib/common/GenericTagMapper.js +4 -4
- package/lib/common/GenericTagTypes.d.ts +5 -4
- package/lib/common/GenericTagTypes.js +2 -2
- package/lib/common/MetadataCollector.d.ts +9 -9
- package/lib/common/MetadataCollector.js +22 -17
- package/lib/common/RandomFileReader.d.ts +1 -1
- package/lib/common/RandomFileReader.js +1 -1
- package/lib/common/RandomUint8ArrayReader.d.ts +1 -1
- package/lib/common/Util.d.ts +2 -6
- package/lib/common/Util.js +9 -11
- package/lib/core.d.ts +7 -9
- package/lib/core.js +10 -7
- package/lib/dsdiff/DsdiffParser.js +26 -14
- package/lib/dsdiff/DsdiffToken.d.ts +2 -2
- package/lib/dsdiff/DsdiffToken.js +1 -0
- package/lib/dsf/DsfChunk.js +1 -0
- package/lib/dsf/DsfParser.js +4 -2
- package/lib/ebml/EbmlIterator.d.ts +52 -0
- package/lib/ebml/EbmlIterator.js +220 -0
- package/lib/ebml/types.d.ts +36 -0
- package/lib/ebml/types.js +10 -0
- package/lib/flac/FlacParser.d.ts +3 -3
- package/lib/flac/FlacParser.js +9 -12
- package/lib/id3v1/ID3v1Parser.d.ts +1 -1
- package/lib/id3v1/ID3v1Parser.js +7 -4
- package/lib/id3v2/AbstractID3Parser.d.ts +1 -1
- package/lib/id3v2/AbstractID3Parser.js +2 -1
- package/lib/id3v2/FrameParser.d.ts +28 -3
- package/lib/id3v2/FrameParser.js +50 -28
- package/lib/id3v2/ID3v22TagMapper.d.ts +1 -1
- package/lib/id3v2/ID3v24TagMapper.d.ts +2 -1
- package/lib/id3v2/ID3v24TagMapper.js +23 -16
- package/lib/id3v2/ID3v2Parser.d.ts +2 -2
- package/lib/id3v2/ID3v2Parser.js +18 -8
- package/lib/iff/index.js +1 -0
- package/lib/index.d.ts +5 -6
- package/lib/index.js +7 -8
- package/lib/lyrics3/Lyrics3.d.ts +1 -1
- package/lib/lyrics3/Lyrics3.js +1 -1
- package/lib/matroska/MatroskaDtd.d.ts +2 -2
- package/lib/matroska/MatroskaDtd.js +247 -239
- package/lib/matroska/MatroskaParser.d.ts +10 -24
- package/lib/matroska/MatroskaParser.js +120 -205
- package/lib/matroska/types.d.ts +12 -46
- package/lib/matroska/types.js +0 -9
- package/lib/mp4/Atom.d.ts +3 -3
- package/lib/mp4/Atom.js +4 -7
- package/lib/mp4/AtomToken.js +2 -1
- package/lib/mp4/MP4Parser.js +29 -20
- package/lib/mp4/MP4TagMapper.d.ts +2 -2
- package/lib/mp4/MP4TagMapper.js +1 -1
- package/lib/mpeg/ExtendedLameHeader.d.ts +4 -4
- package/lib/mpeg/ExtendedLameHeader.js +2 -1
- package/lib/mpeg/MpegParser.d.ts +1 -1
- package/lib/mpeg/MpegParser.js +145 -96
- package/lib/mpeg/ReplayGainDataFormat.d.ts +1 -1
- package/lib/mpeg/ReplayGainDataFormat.js +1 -0
- package/lib/mpeg/XingTag.d.ts +4 -4
- package/lib/mpeg/XingTag.js +5 -4
- package/lib/musepack/index.js +1 -0
- package/lib/musepack/sv7/BitReader.js +14 -17
- package/lib/musepack/sv7/MpcSv7Parser.js +6 -1
- package/lib/musepack/sv7/StreamVersion7.js +1 -0
- package/lib/musepack/sv8/MpcSv8Parser.js +6 -2
- package/lib/musepack/sv8/StreamVersion8.d.ts +1 -1
- package/lib/musepack/sv8/StreamVersion8.js +1 -0
- package/lib/ogg/Ogg.d.ts +1 -1
- package/lib/ogg/Ogg.js +1 -0
- package/lib/ogg/OggParser.d.ts +3 -3
- package/lib/ogg/OggParser.js +25 -16
- package/lib/ogg/opus/Opus.d.ts +1 -1
- package/lib/ogg/opus/Opus.js +1 -0
- package/lib/ogg/opus/OpusParser.d.ts +4 -4
- package/lib/ogg/opus/OpusParser.js +2 -0
- package/lib/ogg/speex/Speex.js +1 -0
- package/lib/ogg/speex/SpeexParser.d.ts +4 -4
- package/lib/ogg/speex/SpeexParser.js +1 -0
- package/lib/ogg/theora/Theora.js +1 -0
- package/lib/ogg/theora/TheoraParser.d.ts +4 -4
- package/lib/ogg/theora/TheoraParser.js +1 -0
- package/lib/ogg/vorbis/Vorbis.d.ts +3 -3
- package/lib/ogg/vorbis/Vorbis.js +22 -11
- package/lib/ogg/vorbis/VorbisDecoder.d.ts +1 -1
- package/lib/ogg/vorbis/VorbisDecoder.js +1 -0
- package/lib/ogg/vorbis/VorbisParser.d.ts +4 -4
- package/lib/ogg/vorbis/VorbisParser.js +3 -2
- package/lib/ogg/vorbis/VorbisTagMapper.d.ts +2 -2
- package/lib/ogg/vorbis/VorbisTagMapper.js +2 -2
- package/lib/riff/RiffChunk.d.ts +3 -3
- package/lib/riff/RiffChunk.js +1 -0
- package/lib/riff/RiffInfoTagMap.d.ts +1 -1
- package/lib/type.d.ts +44 -25
- package/lib/wav/BwfChunk.js +1 -0
- package/lib/wav/WaveChunk.d.ts +1 -1
- package/lib/wav/WaveChunk.js +1 -0
- package/lib/wav/WaveParser.js +27 -17
- package/lib/wavpack/WavPackParser.d.ts +1 -1
- package/lib/wavpack/WavPackParser.js +22 -13
- package/lib/wavpack/WavPackToken.d.ts +13 -17
- package/lib/wavpack/WavPackToken.js +22 -23
- package/package.json +139 -150
package/lib/dsf/DsfParser.js
CHANGED
|
@@ -17,7 +17,7 @@ export class DsfParser extends AbstractID3Parser {
|
|
|
17
17
|
this.metadata.setFormat('lossless', true);
|
|
18
18
|
const dsdChunk = await this.tokenizer.readToken(DsdChunk);
|
|
19
19
|
if (dsdChunk.metadataPointer === BigInt(0)) {
|
|
20
|
-
debug(
|
|
20
|
+
debug("No ID3v2 tag present");
|
|
21
21
|
}
|
|
22
22
|
else {
|
|
23
23
|
debug(`expect ID3v2 at offset=${dsdChunk.metadataPointer}`);
|
|
@@ -32,7 +32,7 @@ export class DsfParser extends AbstractID3Parser {
|
|
|
32
32
|
const chunkHeader = await this.tokenizer.readToken(ChunkHeader);
|
|
33
33
|
debug(`Parsing chunk name=${chunkHeader.id} size=${chunkHeader.size}`);
|
|
34
34
|
switch (chunkHeader.id) {
|
|
35
|
-
case 'fmt ':
|
|
35
|
+
case 'fmt ': {
|
|
36
36
|
const formatChunk = await this.tokenizer.readToken(FormatChunk);
|
|
37
37
|
this.metadata.setFormat('numberOfChannels', formatChunk.channelNum);
|
|
38
38
|
this.metadata.setFormat('sampleRate', formatChunk.samplingFrequency);
|
|
@@ -42,6 +42,7 @@ export class DsfParser extends AbstractID3Parser {
|
|
|
42
42
|
const bitrate = formatChunk.bitsPerSample * formatChunk.samplingFrequency * formatChunk.channelNum;
|
|
43
43
|
this.metadata.setFormat('bitrate', bitrate);
|
|
44
44
|
return; // We got what we want, stop further processing of chunks
|
|
45
|
+
}
|
|
45
46
|
default:
|
|
46
47
|
this.tokenizer.ignore(Number(chunkHeader.size) - ChunkHeader.len);
|
|
47
48
|
break;
|
|
@@ -50,3 +51,4 @@ export class DsfParser extends AbstractID3Parser {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
}
|
|
54
|
+
//# sourceMappingURL=DsfParser.js.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type ITokenizer } from 'strtok3';
|
|
2
|
+
import { type IElementType, type ITree, type ValueType } from './types.js';
|
|
3
|
+
export interface ILinkedElementType extends IElementType {
|
|
4
|
+
id: number;
|
|
5
|
+
parent: ILinkedElementType | undefined;
|
|
6
|
+
readonly container?: {
|
|
7
|
+
[id: number]: ILinkedElementType;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare enum ParseAction {
|
|
11
|
+
ReadNext = 0,// Continue reading the next elements
|
|
12
|
+
IgnoreElement = 2,// Ignore (do not read) this element
|
|
13
|
+
SkipSiblings = 3,// Skip all remaining elements at the same level
|
|
14
|
+
TerminateParsing = 4,// Terminate the parsing process
|
|
15
|
+
SkipElement = 5
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @return true, to quit the parser
|
|
19
|
+
*/
|
|
20
|
+
export type IElementListener = {
|
|
21
|
+
startNext: (dtdElement: ILinkedElementType) => ParseAction;
|
|
22
|
+
elementValue: (dtdElement: ILinkedElementType, value: ValueType, offset: number) => Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Extensible Binary Meta Language (EBML) iterator
|
|
26
|
+
* https://en.wikipedia.org/wiki/Extensible_Binary_Meta_Language
|
|
27
|
+
* http://matroska.sourceforge.net/technical/specs/rfc/index.html
|
|
28
|
+
*
|
|
29
|
+
* WEBM VP8 AUDIO FILE
|
|
30
|
+
*/
|
|
31
|
+
export declare class EbmlIterator {
|
|
32
|
+
private tokenizer;
|
|
33
|
+
private padding;
|
|
34
|
+
private parserMap;
|
|
35
|
+
private ebmlMaxIDLength;
|
|
36
|
+
private ebmlMaxSizeLength;
|
|
37
|
+
/**
|
|
38
|
+
* @param {ITokenizer} tokenizer Input
|
|
39
|
+
* @param tokenizer
|
|
40
|
+
*/
|
|
41
|
+
constructor(tokenizer: ITokenizer);
|
|
42
|
+
iterate(dtdElement: IElementType, posDone: number, listener: IElementListener): Promise<ITree>;
|
|
43
|
+
private parseContainer;
|
|
44
|
+
private readVintData;
|
|
45
|
+
private readElement;
|
|
46
|
+
private readFloat;
|
|
47
|
+
private readFlag;
|
|
48
|
+
private readUint;
|
|
49
|
+
private readString;
|
|
50
|
+
private readBuffer;
|
|
51
|
+
}
|
|
52
|
+
export declare function getElementPath(element: ILinkedElementType): string;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { Float32_BE, Float64_BE, StringType, UINT8 } from 'token-types';
|
|
2
|
+
import initDebug from 'debug';
|
|
3
|
+
import { EndOfStreamError } from 'strtok3';
|
|
4
|
+
import { DataType } from './types.js';
|
|
5
|
+
import * as Token from 'token-types';
|
|
6
|
+
const debug = initDebug('music-metadata:parser:ebml');
|
|
7
|
+
export var ParseAction;
|
|
8
|
+
(function (ParseAction) {
|
|
9
|
+
ParseAction[ParseAction["ReadNext"] = 0] = "ReadNext";
|
|
10
|
+
ParseAction[ParseAction["IgnoreElement"] = 2] = "IgnoreElement";
|
|
11
|
+
ParseAction[ParseAction["SkipSiblings"] = 3] = "SkipSiblings";
|
|
12
|
+
ParseAction[ParseAction["TerminateParsing"] = 4] = "TerminateParsing";
|
|
13
|
+
ParseAction[ParseAction["SkipElement"] = 5] = "SkipElement"; // Consider the element has read, assume position is at the next element
|
|
14
|
+
})(ParseAction || (ParseAction = {}));
|
|
15
|
+
/**
|
|
16
|
+
* Extensible Binary Meta Language (EBML) iterator
|
|
17
|
+
* https://en.wikipedia.org/wiki/Extensible_Binary_Meta_Language
|
|
18
|
+
* http://matroska.sourceforge.net/technical/specs/rfc/index.html
|
|
19
|
+
*
|
|
20
|
+
* WEBM VP8 AUDIO FILE
|
|
21
|
+
*/
|
|
22
|
+
export class EbmlIterator {
|
|
23
|
+
/**
|
|
24
|
+
* @param {ITokenizer} tokenizer Input
|
|
25
|
+
* @param tokenizer
|
|
26
|
+
*/
|
|
27
|
+
constructor(tokenizer) {
|
|
28
|
+
this.tokenizer = tokenizer;
|
|
29
|
+
this.padding = 0;
|
|
30
|
+
this.parserMap = new Map();
|
|
31
|
+
this.ebmlMaxIDLength = 4;
|
|
32
|
+
this.ebmlMaxSizeLength = 8;
|
|
33
|
+
this.parserMap.set(DataType.uint, e => this.readUint(e));
|
|
34
|
+
this.parserMap.set(DataType.string, e => this.readString(e));
|
|
35
|
+
this.parserMap.set(DataType.binary, e => this.readBuffer(e));
|
|
36
|
+
this.parserMap.set(DataType.uid, async (e) => this.readBuffer(e));
|
|
37
|
+
this.parserMap.set(DataType.bool, e => this.readFlag(e));
|
|
38
|
+
this.parserMap.set(DataType.float, e => this.readFloat(e));
|
|
39
|
+
}
|
|
40
|
+
async iterate(dtdElement, posDone, listener) {
|
|
41
|
+
return this.parseContainer(linkParents(dtdElement), posDone, listener);
|
|
42
|
+
}
|
|
43
|
+
async parseContainer(dtdElement, posDone, listener) {
|
|
44
|
+
const tree = {};
|
|
45
|
+
while (this.tokenizer.position < posDone) {
|
|
46
|
+
let element;
|
|
47
|
+
const elementPosition = this.tokenizer.position;
|
|
48
|
+
try {
|
|
49
|
+
element = await this.readElement();
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error instanceof EndOfStreamError) {
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
const child = dtdElement.container[element.id];
|
|
58
|
+
if (child) {
|
|
59
|
+
const action = listener.startNext(child);
|
|
60
|
+
switch (action) {
|
|
61
|
+
case ParseAction.ReadNext:
|
|
62
|
+
{
|
|
63
|
+
if (element.id === 0x1F43B675) {
|
|
64
|
+
// Hack to ignore remaining segment, when cluster element received
|
|
65
|
+
// await this.tokenizer.ignore(posDone - this.tokenizer.position);
|
|
66
|
+
// break;
|
|
67
|
+
}
|
|
68
|
+
debug(`Read element: name=${getElementPath(child)}{id=0x${element.id.toString(16)}, container=${!!child.container}} at position=${elementPosition}`);
|
|
69
|
+
if (child.container) {
|
|
70
|
+
const res = await this.parseContainer(child, element.len >= 0 ? this.tokenizer.position + element.len : -1, listener);
|
|
71
|
+
if (child.multiple) {
|
|
72
|
+
if (!tree[child.name]) {
|
|
73
|
+
tree[child.name] = [];
|
|
74
|
+
}
|
|
75
|
+
tree[child.name].push(res);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
tree[child.name] = res;
|
|
79
|
+
}
|
|
80
|
+
await listener.elementValue(child, res, elementPosition);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const parser = this.parserMap.get(child.value);
|
|
84
|
+
if (typeof parser === 'function') {
|
|
85
|
+
const value = await parser(element);
|
|
86
|
+
tree[child.name] = value;
|
|
87
|
+
await listener.elementValue(child, value, elementPosition);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case ParseAction.SkipElement:
|
|
93
|
+
debug(`Go to next element: name=${getElementPath(child)}, element.id=0x${element.id}, container=${!!child.container} at position=${elementPosition}`);
|
|
94
|
+
break;
|
|
95
|
+
case ParseAction.IgnoreElement:
|
|
96
|
+
debug(`Ignore element: name=${getElementPath(child)}, element.id=0x${element.id}, container=${!!child.container} at position=${elementPosition}`);
|
|
97
|
+
await this.tokenizer.ignore(element.len);
|
|
98
|
+
break;
|
|
99
|
+
case ParseAction.SkipSiblings:
|
|
100
|
+
debug(`Ignore remaining container, at: name=${getElementPath(child)}, element.id=0x${element.id}, container=${!!child.container} at position=${elementPosition}`);
|
|
101
|
+
await this.tokenizer.ignore(posDone - this.tokenizer.position);
|
|
102
|
+
break;
|
|
103
|
+
case ParseAction.TerminateParsing:
|
|
104
|
+
debug(`Terminate parsing at element: name=${getElementPath(child)}, element.id=0x${element.id}, container=${!!child.container} at position=${elementPosition}`);
|
|
105
|
+
return tree;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
switch (element.id) {
|
|
110
|
+
case 0xec: // void
|
|
111
|
+
this.padding += element.len;
|
|
112
|
+
await this.tokenizer.ignore(element.len);
|
|
113
|
+
break;
|
|
114
|
+
default:
|
|
115
|
+
debug(`parseEbml: parent=${getElementPath(dtdElement)}, unknown child: id=${element.id.toString(16)} at position=${elementPosition}`);
|
|
116
|
+
this.padding += element.len;
|
|
117
|
+
await this.tokenizer.ignore(element.len);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return tree;
|
|
122
|
+
}
|
|
123
|
+
async readVintData(maxLength) {
|
|
124
|
+
const msb = await this.tokenizer.peekNumber(UINT8);
|
|
125
|
+
let mask = 0x80;
|
|
126
|
+
let oc = 1;
|
|
127
|
+
// Calculate VINT_WIDTH
|
|
128
|
+
while ((msb & mask) === 0) {
|
|
129
|
+
if (oc > maxLength) {
|
|
130
|
+
throw new Error('VINT value exceeding maximum size');
|
|
131
|
+
}
|
|
132
|
+
++oc;
|
|
133
|
+
mask >>= 1;
|
|
134
|
+
}
|
|
135
|
+
const id = new Uint8Array(oc);
|
|
136
|
+
await this.tokenizer.readBuffer(id);
|
|
137
|
+
return id;
|
|
138
|
+
}
|
|
139
|
+
async readElement() {
|
|
140
|
+
const id = await this.readVintData(this.ebmlMaxIDLength);
|
|
141
|
+
const lenField = await this.readVintData(this.ebmlMaxSizeLength);
|
|
142
|
+
lenField[0] ^= 0x80 >> (lenField.length - 1);
|
|
143
|
+
return {
|
|
144
|
+
id: readUIntBE(id, id.length),
|
|
145
|
+
len: readUIntBE(lenField, lenField.length)
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async readFloat(e) {
|
|
149
|
+
switch (e.len) {
|
|
150
|
+
case 0:
|
|
151
|
+
return 0.0;
|
|
152
|
+
case 4:
|
|
153
|
+
return this.tokenizer.readNumber(Float32_BE);
|
|
154
|
+
case 8:
|
|
155
|
+
return this.tokenizer.readNumber(Float64_BE);
|
|
156
|
+
case 10:
|
|
157
|
+
return this.tokenizer.readNumber(Float64_BE);
|
|
158
|
+
default:
|
|
159
|
+
throw new Error(`Invalid IEEE-754 float length: ${e.len}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async readFlag(e) {
|
|
163
|
+
return (await this.readUint(e)) === 1;
|
|
164
|
+
}
|
|
165
|
+
async readUint(e) {
|
|
166
|
+
const buf = await this.readBuffer(e);
|
|
167
|
+
return readUIntBE(buf, e.len);
|
|
168
|
+
}
|
|
169
|
+
async readString(e) {
|
|
170
|
+
const rawString = await this.tokenizer.readToken(new StringType(e.len, 'utf-8'));
|
|
171
|
+
return rawString.replace(/\x00.*$/g, '');
|
|
172
|
+
}
|
|
173
|
+
async readBuffer(e) {
|
|
174
|
+
const buf = new Uint8Array(e.len);
|
|
175
|
+
await this.tokenizer.readBuffer(buf);
|
|
176
|
+
return buf;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function readUIntBE(buf, len) {
|
|
180
|
+
return Number(readUIntBeAsBigInt(buf, len));
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Reeds an unsigned integer from a big endian buffer of length `len`
|
|
184
|
+
* @param buf Buffer to decode from
|
|
185
|
+
* @param len Number of bytes
|
|
186
|
+
* @private
|
|
187
|
+
*/
|
|
188
|
+
function readUIntBeAsBigInt(buf, len) {
|
|
189
|
+
const normalizedNumber = new Uint8Array(8);
|
|
190
|
+
const cleanNumber = buf.subarray(0, len);
|
|
191
|
+
try {
|
|
192
|
+
normalizedNumber.set(cleanNumber, 8 - len);
|
|
193
|
+
return Token.UINT64_BE.get(normalizedNumber, 0);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
return BigInt(-1);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function linkParents(element) {
|
|
200
|
+
if (element.container) {
|
|
201
|
+
Object.keys(element.container)
|
|
202
|
+
.map(id => {
|
|
203
|
+
const child = element.container[id];
|
|
204
|
+
child.id = Number.parseInt(id);
|
|
205
|
+
return child;
|
|
206
|
+
}).forEach(child => {
|
|
207
|
+
child.parent = element;
|
|
208
|
+
linkParents(child);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return element;
|
|
212
|
+
}
|
|
213
|
+
export function getElementPath(element) {
|
|
214
|
+
let path = '';
|
|
215
|
+
if (element.parent && element.parent.name !== 'dtd') {
|
|
216
|
+
path += `${getElementPath(element.parent)}/`;
|
|
217
|
+
}
|
|
218
|
+
return path + element.name;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=EbmlIterator.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface ITree {
|
|
2
|
+
[name: string]: string | number | boolean | Uint8Array | ITree | ITree[];
|
|
3
|
+
}
|
|
4
|
+
export declare enum DataType {
|
|
5
|
+
'string' = 0,
|
|
6
|
+
uint = 1,
|
|
7
|
+
uid = 2,
|
|
8
|
+
bool = 3,
|
|
9
|
+
binary = 4,
|
|
10
|
+
float = 5
|
|
11
|
+
}
|
|
12
|
+
export type ValueType = string | number | Uint8Array | boolean | ITree | ITree[];
|
|
13
|
+
export interface IHeader {
|
|
14
|
+
id: number;
|
|
15
|
+
len: number;
|
|
16
|
+
}
|
|
17
|
+
export interface IEbmlElements {
|
|
18
|
+
version?: number;
|
|
19
|
+
readVersion?: number;
|
|
20
|
+
maxIDWidth?: number;
|
|
21
|
+
maxSizeWidth?: number;
|
|
22
|
+
docType?: string;
|
|
23
|
+
docTypeVersion?: number;
|
|
24
|
+
docTypeReadVersion?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface IElementType {
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly value?: DataType;
|
|
29
|
+
readonly container?: {
|
|
30
|
+
[id: number]: IElementType;
|
|
31
|
+
};
|
|
32
|
+
readonly multiple?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface IEbmlDoc {
|
|
35
|
+
ebml: IEbmlElements;
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export var DataType;
|
|
2
|
+
(function (DataType) {
|
|
3
|
+
DataType[DataType["string"] = 0] = "string";
|
|
4
|
+
DataType[DataType["uint"] = 1] = "uint";
|
|
5
|
+
DataType[DataType["uid"] = 2] = "uid";
|
|
6
|
+
DataType[DataType["bool"] = 3] = "bool";
|
|
7
|
+
DataType[DataType["binary"] = 4] = "binary";
|
|
8
|
+
DataType[DataType["float"] = 5] = "float";
|
|
9
|
+
})(DataType || (DataType = {}));
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
package/lib/flac/FlacParser.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ITokenizer } from 'strtok3';
|
|
2
2
|
import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
|
|
3
|
-
import { INativeMetadataCollector } from '../common/MetadataCollector.js';
|
|
4
|
-
import { IOptions } from '../type.js';
|
|
5
|
-
import { ITokenParser } from '../ParserFactory.js';
|
|
3
|
+
import type { INativeMetadataCollector } from '../common/MetadataCollector.js';
|
|
4
|
+
import type { IOptions } from '../type.js';
|
|
5
|
+
import type { ITokenParser } from '../ParserFactory.js';
|
|
6
6
|
export declare class FlacParser extends AbstractID3Parser {
|
|
7
7
|
private vorbisParser;
|
|
8
8
|
private padding;
|
package/lib/flac/FlacParser.js
CHANGED
|
@@ -45,7 +45,7 @@ export class FlacParser extends AbstractID3Parser {
|
|
|
45
45
|
let blockHeader;
|
|
46
46
|
do {
|
|
47
47
|
// Read block header
|
|
48
|
-
blockHeader = await this.tokenizer.readToken(
|
|
48
|
+
blockHeader = await this.tokenizer.readToken(BlockHeader);
|
|
49
49
|
// Parse block data
|
|
50
50
|
await this.parseDataBlock(blockHeader);
|
|
51
51
|
} while (!blockHeader.lastBlock);
|
|
@@ -74,7 +74,7 @@ export class FlacParser extends AbstractID3Parser {
|
|
|
74
74
|
await this.parsePicture(blockHeader.length);
|
|
75
75
|
return;
|
|
76
76
|
default:
|
|
77
|
-
this.metadata.addWarning(
|
|
77
|
+
this.metadata.addWarning(`Unknown block type: ${blockHeader.type}`);
|
|
78
78
|
}
|
|
79
79
|
// Ignore data block
|
|
80
80
|
return this.tokenizer.ignore(blockHeader.length).then();
|
|
@@ -83,9 +83,9 @@ export class FlacParser extends AbstractID3Parser {
|
|
|
83
83
|
* Parse STREAMINFO
|
|
84
84
|
*/
|
|
85
85
|
async parseBlockStreamInfo(dataLen) {
|
|
86
|
-
if (dataLen !==
|
|
86
|
+
if (dataLen !== BlockStreamInfo.len)
|
|
87
87
|
throw new Error('Unexpected block-stream-info length');
|
|
88
|
-
const streamInfo = await this.tokenizer.readToken(
|
|
88
|
+
const streamInfo = await this.tokenizer.readToken(BlockStreamInfo);
|
|
89
89
|
this.metadata.setFormat('container', 'FLAC');
|
|
90
90
|
this.metadata.setFormat('codec', 'FLAC');
|
|
91
91
|
this.metadata.setFormat('lossless', true);
|
|
@@ -115,15 +115,11 @@ export class FlacParser extends AbstractID3Parser {
|
|
|
115
115
|
if (this.options.skipCovers) {
|
|
116
116
|
return this.tokenizer.ignore(dataLen);
|
|
117
117
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this.vorbisParser.addTag('METADATA_BLOCK_PICTURE', picture);
|
|
121
|
-
}
|
|
118
|
+
const picture = await this.tokenizer.readToken(new VorbisPictureToken(dataLen));
|
|
119
|
+
this.vorbisParser.addTag('METADATA_BLOCK_PICTURE', picture);
|
|
122
120
|
}
|
|
123
121
|
}
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
Metadata.BlockHeader = {
|
|
122
|
+
const BlockHeader = {
|
|
127
123
|
len: 4,
|
|
128
124
|
get: (buf, off) => {
|
|
129
125
|
return {
|
|
@@ -137,7 +133,7 @@ Metadata.BlockHeader = {
|
|
|
137
133
|
* METADATA_BLOCK_DATA
|
|
138
134
|
* Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo
|
|
139
135
|
*/
|
|
140
|
-
|
|
136
|
+
const BlockStreamInfo = {
|
|
141
137
|
len: 34,
|
|
142
138
|
get: (buf, off) => {
|
|
143
139
|
return {
|
|
@@ -171,3 +167,4 @@ Metadata.BlockStreamInfo = {
|
|
|
171
167
|
};
|
|
172
168
|
}
|
|
173
169
|
};
|
|
170
|
+
//# sourceMappingURL=FlacParser.js.map
|
package/lib/id3v1/ID3v1Parser.js
CHANGED
|
@@ -66,12 +66,13 @@ const Iid3v1Token = {
|
|
|
66
66
|
} : null;
|
|
67
67
|
}
|
|
68
68
|
};
|
|
69
|
-
class Id3v1StringType
|
|
69
|
+
class Id3v1StringType {
|
|
70
70
|
constructor(len) {
|
|
71
|
-
|
|
71
|
+
this.len = len;
|
|
72
|
+
this.stringType = new StringType(len, 'latin1');
|
|
72
73
|
}
|
|
73
74
|
get(buf, off) {
|
|
74
|
-
let value =
|
|
75
|
+
let value = this.stringType.get(buf, off);
|
|
75
76
|
value = util.trimRightNull(value);
|
|
76
77
|
value = value.trim();
|
|
77
78
|
return value.length > 0 ? value : undefined;
|
|
@@ -103,7 +104,8 @@ export class ID3v1Parser extends BasicParser {
|
|
|
103
104
|
const header = await this.tokenizer.readToken(Iid3v1Token, offset);
|
|
104
105
|
if (header) {
|
|
105
106
|
debug('ID3v1 header found at: pos=%s', this.tokenizer.fileInfo.size - Iid3v1Token.len);
|
|
106
|
-
|
|
107
|
+
const props = ['title', 'artist', 'album', 'comment', 'track', 'year'];
|
|
108
|
+
for (const id of props) {
|
|
107
109
|
if (header[id] && header[id] !== '')
|
|
108
110
|
await this.addTag(id, header[id]);
|
|
109
111
|
}
|
|
@@ -127,3 +129,4 @@ export async function hasID3v1Header(reader) {
|
|
|
127
129
|
}
|
|
128
130
|
return false;
|
|
129
131
|
}
|
|
132
|
+
//# sourceMappingURL=ID3v1Parser.js.map
|
|
@@ -22,7 +22,7 @@ export class AbstractID3Parser extends BasicParser {
|
|
|
22
22
|
}
|
|
23
23
|
catch (err) {
|
|
24
24
|
if (err instanceof EndOfStreamError) {
|
|
25
|
-
debug(
|
|
25
|
+
debug("End-of-stream");
|
|
26
26
|
}
|
|
27
27
|
else {
|
|
28
28
|
throw err;
|
|
@@ -54,3 +54,4 @@ export class AbstractID3Parser extends BasicParser {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
//# sourceMappingURL=AbstractID3Parser.js.map
|
|
@@ -1,5 +1,29 @@
|
|
|
1
|
-
import { ID3v2MajorVersion, ITextEncoding } from './ID3v2Token.js';
|
|
2
|
-
import { IWarningCollector } from '../common/MetadataCollector.js';
|
|
1
|
+
import { type ID3v2MajorVersion, type ITextEncoding } from './ID3v2Token.js';
|
|
2
|
+
import type { IWarningCollector } from '../common/MetadataCollector.js';
|
|
3
|
+
interface ICustomTag {
|
|
4
|
+
owner_identifier: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ICustomDataTag extends ICustomTag {
|
|
7
|
+
data: Uint8Array;
|
|
8
|
+
}
|
|
9
|
+
export interface IIdentifierTag extends ICustomTag {
|
|
10
|
+
identifier: Uint8Array;
|
|
11
|
+
}
|
|
12
|
+
export interface ITextTag {
|
|
13
|
+
description: string;
|
|
14
|
+
text: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface IPopularimeter {
|
|
17
|
+
email: string;
|
|
18
|
+
rating: number;
|
|
19
|
+
counter: number;
|
|
20
|
+
}
|
|
21
|
+
export interface IGeneralEncapsulatedObject {
|
|
22
|
+
type: string;
|
|
23
|
+
filename: string;
|
|
24
|
+
description: string;
|
|
25
|
+
data: Uint8Array;
|
|
26
|
+
}
|
|
3
27
|
export declare function parseGenre(origVal: string): string[];
|
|
4
28
|
export declare class FrameParser {
|
|
5
29
|
private major;
|
|
@@ -10,7 +34,7 @@ export declare class FrameParser {
|
|
|
10
34
|
* @param warningCollector - Used to collect decode issue
|
|
11
35
|
*/
|
|
12
36
|
constructor(major: ID3v2MajorVersion, warningCollector: IWarningCollector);
|
|
13
|
-
readData(uint8Array: Uint8Array, type: string, includeCovers: boolean):
|
|
37
|
+
readData(uint8Array: Uint8Array, type: string, includeCovers: boolean): unknown;
|
|
14
38
|
protected static readNullTerminatedString(uint8Array: Uint8Array, encoding: ITextEncoding): {
|
|
15
39
|
text: string;
|
|
16
40
|
len: number;
|
|
@@ -33,3 +57,4 @@ export declare class FrameParser {
|
|
|
33
57
|
private static readIdentifierAndData;
|
|
34
58
|
private static getNullTerminatorLength;
|
|
35
59
|
}
|
|
60
|
+
export {};
|