music-metadata 10.2.0 → 10.3.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 +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 +2 -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/lib/ebml/EbmlIterator.js
CHANGED
|
@@ -3,7 +3,10 @@ import initDebug from 'debug';
|
|
|
3
3
|
import { EndOfStreamError } from 'strtok3';
|
|
4
4
|
import { DataType } from './types.js';
|
|
5
5
|
import * as Token from 'token-types';
|
|
6
|
+
import { makeUnexpectedFileContentError } from '../ParseError.js';
|
|
6
7
|
const debug = initDebug('music-metadata:parser:ebml');
|
|
8
|
+
export class EbmlContentError extends makeUnexpectedFileContentError('EBML') {
|
|
9
|
+
}
|
|
7
10
|
export var ParseAction;
|
|
8
11
|
(function (ParseAction) {
|
|
9
12
|
ParseAction[ParseAction["ReadNext"] = 0] = "ReadNext";
|
|
@@ -127,7 +130,7 @@ export class EbmlIterator {
|
|
|
127
130
|
// Calculate VINT_WIDTH
|
|
128
131
|
while ((msb & mask) === 0) {
|
|
129
132
|
if (oc > maxLength) {
|
|
130
|
-
throw new
|
|
133
|
+
throw new EbmlContentError('VINT value exceeding maximum size');
|
|
131
134
|
}
|
|
132
135
|
++oc;
|
|
133
136
|
mask >>= 1;
|
|
@@ -156,7 +159,7 @@ export class EbmlIterator {
|
|
|
156
159
|
case 10:
|
|
157
160
|
return this.tokenizer.readNumber(Float64_BE);
|
|
158
161
|
default:
|
|
159
|
-
throw new
|
|
162
|
+
throw new EbmlContentError(`Invalid IEEE-754 float length: ${e.len}`);
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
async readFlag(e) {
|
package/lib/flac/FlacParser.js
CHANGED
|
@@ -6,7 +6,10 @@ import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
|
|
|
6
6
|
import { FourCcToken } from '../common/FourCC.js';
|
|
7
7
|
import { VorbisParser } from '../ogg/vorbis/VorbisParser.js';
|
|
8
8
|
import { VorbisDecoder } from '../ogg/vorbis/VorbisDecoder.js';
|
|
9
|
+
import { makeUnexpectedFileContentError } from '../ParseError.js';
|
|
9
10
|
const debug = initDebug('music-metadata:parser:FLAC');
|
|
11
|
+
class FlacContentError extends makeUnexpectedFileContentError('FLAC') {
|
|
12
|
+
}
|
|
10
13
|
/**
|
|
11
14
|
* FLAC supports up to 128 kinds of metadata blocks; currently the following are defined:
|
|
12
15
|
* ref: https://xiph.org/flac/format.html#metadata_block
|
|
@@ -40,7 +43,7 @@ export class FlacParser extends AbstractID3Parser {
|
|
|
40
43
|
async postId3v2Parse() {
|
|
41
44
|
const fourCC = await this.tokenizer.readToken(FourCcToken);
|
|
42
45
|
if (fourCC.toString() !== 'fLaC') {
|
|
43
|
-
throw new
|
|
46
|
+
throw new FlacContentError('Invalid FLAC preamble');
|
|
44
47
|
}
|
|
45
48
|
let blockHeader;
|
|
46
49
|
do {
|
|
@@ -84,7 +87,7 @@ export class FlacParser extends AbstractID3Parser {
|
|
|
84
87
|
*/
|
|
85
88
|
async parseBlockStreamInfo(dataLen) {
|
|
86
89
|
if (dataLen !== BlockStreamInfo.len)
|
|
87
|
-
throw new
|
|
90
|
+
throw new FlacContentError('Unexpected block-stream-info length');
|
|
88
91
|
const streamInfo = await this.tokenizer.readToken(BlockStreamInfo);
|
|
89
92
|
this.metadata.setFormat('container', 'FLAC');
|
|
90
93
|
this.metadata.setFormat('codec', 'FLAC');
|
|
@@ -57,4 +57,18 @@ export declare class FrameParser {
|
|
|
57
57
|
private static readIdentifierAndData;
|
|
58
58
|
private static getNullTerminatorLength;
|
|
59
59
|
}
|
|
60
|
+
declare const Id3v2ContentError_base: {
|
|
61
|
+
new (message: string): {
|
|
62
|
+
readonly fileType: string;
|
|
63
|
+
toString(): string;
|
|
64
|
+
name: "UnexpectedFileContentError";
|
|
65
|
+
message: string;
|
|
66
|
+
stack?: string;
|
|
67
|
+
};
|
|
68
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
69
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
70
|
+
stackTraceLimit: number;
|
|
71
|
+
};
|
|
72
|
+
export declare class Id3v2ContentError extends Id3v2ContentError_base {
|
|
73
|
+
}
|
|
60
74
|
export {};
|
package/lib/id3v2/FrameParser.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as Token from 'token-types';
|
|
|
3
3
|
import * as util from '../common/Util.js';
|
|
4
4
|
import { AttachedPictureType, SyncTextHeader, TextEncodingToken, TextHeader } from './ID3v2Token.js';
|
|
5
5
|
import { Genres } from '../id3v1/ID3v1Parser.js';
|
|
6
|
+
import { makeUnexpectedFileContentError } from '../ParseError.js';
|
|
6
7
|
const debug = initDebug('music-metadata:id3v2:frame-parser');
|
|
7
8
|
const defaultEnc = 'latin1'; // latin1 == iso-8859-1;
|
|
8
9
|
export function parseGenre(origVal) {
|
|
@@ -158,7 +159,7 @@ export class FrameParser {
|
|
|
158
159
|
offset = fzero + 1;
|
|
159
160
|
break;
|
|
160
161
|
default:
|
|
161
|
-
throw
|
|
162
|
+
throw makeUnexpectedMajorVersionError(this.major);
|
|
162
163
|
}
|
|
163
164
|
pic.format = FrameParser.fixPictureMimeType(pic.format);
|
|
164
165
|
pic.type = AttachedPictureType[uint8Array[offset]];
|
|
@@ -370,4 +371,9 @@ export class FrameParser {
|
|
|
370
371
|
return enc === 'utf-16le' ? 2 : 1;
|
|
371
372
|
}
|
|
372
373
|
}
|
|
374
|
+
export class Id3v2ContentError extends makeUnexpectedFileContentError('id3v2') {
|
|
375
|
+
}
|
|
376
|
+
function makeUnexpectedMajorVersionError(majorVer) {
|
|
377
|
+
throw new Id3v2ContentError(`Unexpected majorVer: ${majorVer}`);
|
|
378
|
+
}
|
|
373
379
|
//# sourceMappingURL=FrameParser.js.map
|
package/lib/id3v2/ID3v2Parser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Token from 'token-types';
|
|
2
2
|
import * as util from '../common/Util.js';
|
|
3
|
-
import { FrameParser } from './FrameParser.js';
|
|
3
|
+
import { FrameParser, Id3v2ContentError } from './FrameParser.js';
|
|
4
4
|
import { ExtendedHeader, ID3v2Header, UINT32SYNCSAFE } from './ID3v2Token.js';
|
|
5
5
|
const asciiDecoder = new TextDecoder('ascii');
|
|
6
6
|
export class ID3v2Parser {
|
|
@@ -34,7 +34,7 @@ export class ID3v2Parser {
|
|
|
34
34
|
case 4:
|
|
35
35
|
return 10;
|
|
36
36
|
default:
|
|
37
|
-
throw
|
|
37
|
+
throw makeUnexpectedMajorVersionError(majorVer);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
static readFrameFlags(b) {
|
|
@@ -68,7 +68,7 @@ export class ID3v2Parser {
|
|
|
68
68
|
}
|
|
69
69
|
return frameParser.readData(uint8Array, frameHeader.id, includeCovers);
|
|
70
70
|
default:
|
|
71
|
-
throw
|
|
71
|
+
throw makeUnexpectedMajorVersionError(majorVer);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
@@ -86,7 +86,7 @@ export class ID3v2Parser {
|
|
|
86
86
|
this.options = options;
|
|
87
87
|
const id3Header = await this.tokenizer.readToken(ID3v2Header);
|
|
88
88
|
if (id3Header.fileIdentifier !== 'ID3') {
|
|
89
|
-
throw new
|
|
89
|
+
throw new Id3v2ContentError('expected ID3-header file-identifier \'ID3\' was not found');
|
|
90
90
|
}
|
|
91
91
|
this.id3Header = id3Header;
|
|
92
92
|
this.headerType = (`ID3v2.${id3Header.version.major}`);
|
|
@@ -168,9 +168,12 @@ export class ID3v2Parser {
|
|
|
168
168
|
}
|
|
169
169
|
break;
|
|
170
170
|
default:
|
|
171
|
-
throw
|
|
171
|
+
throw makeUnexpectedMajorVersionError(majorVer);
|
|
172
172
|
}
|
|
173
173
|
return header;
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
|
+
function makeUnexpectedMajorVersionError(majorVer) {
|
|
177
|
+
throw new Id3v2ContentError(`Unexpected majorVer: ${majorVer}`);
|
|
178
|
+
}
|
|
176
179
|
//# sourceMappingURL=ID3v2Parser.js.map
|
package/lib/mp4/AtomToken.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import type { IToken, IGetToken } from 'strtok3';
|
|
2
|
+
declare const Mp4ContentError_base: {
|
|
3
|
+
new (message: string): {
|
|
4
|
+
readonly fileType: string;
|
|
5
|
+
toString(): string;
|
|
6
|
+
name: "UnexpectedFileContentError";
|
|
7
|
+
message: string;
|
|
8
|
+
stack?: string;
|
|
9
|
+
};
|
|
10
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
11
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
12
|
+
stackTraceLimit: number;
|
|
13
|
+
};
|
|
14
|
+
export declare class Mp4ContentError extends Mp4ContentError_base {
|
|
15
|
+
}
|
|
2
16
|
interface IVersionAndFlags {
|
|
3
17
|
/**
|
|
4
18
|
* A 1-byte specification of the version
|
package/lib/mp4/AtomToken.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import * as Token from 'token-types';
|
|
2
2
|
import initDebug from 'debug';
|
|
3
3
|
import { FourCcToken } from '../common/FourCC.js';
|
|
4
|
+
import { makeUnexpectedFileContentError } from '../ParseError.js';
|
|
4
5
|
const debug = initDebug('music-metadata:parser:MP4:atom');
|
|
6
|
+
export class Mp4ContentError extends makeUnexpectedFileContentError('MP4') {
|
|
7
|
+
}
|
|
5
8
|
export const Header = {
|
|
6
9
|
len: 8,
|
|
7
10
|
get: (buf, off) => {
|
|
8
11
|
const length = Token.UINT32_BE.get(buf, off);
|
|
9
12
|
if (length < 0)
|
|
10
|
-
throw new
|
|
13
|
+
throw new Mp4ContentError('Invalid atom header length');
|
|
11
14
|
return {
|
|
12
15
|
length: BigInt(length),
|
|
13
16
|
name: new Token.StringType(4, 'latin1').get(buf, off + 4)
|
|
@@ -66,7 +69,7 @@ export class FixedLengthAtom {
|
|
|
66
69
|
constructor(len, expLen, atomId) {
|
|
67
70
|
this.len = len;
|
|
68
71
|
if (len < expLen) {
|
|
69
|
-
throw new
|
|
72
|
+
throw new Mp4ContentError(`Atom ${atomId} expected to be ${expLen}, but specifies ${len} bytes long.`);
|
|
70
73
|
}
|
|
71
74
|
if (len > expLen) {
|
|
72
75
|
debug(`Warning: atom ${atomId} expected to be ${expLen}, but was actually ${len} bytes long.`);
|
|
@@ -381,7 +384,7 @@ function readTokenTable(buf, token, off, remainingLen, numberOfEntries) {
|
|
|
381
384
|
if (remainingLen === 0)
|
|
382
385
|
return [];
|
|
383
386
|
if (remainingLen !== numberOfEntries * token.len)
|
|
384
|
-
throw new
|
|
387
|
+
throw new Mp4ContentError('mismatch number-of-entries with remaining atom-length');
|
|
385
388
|
const entries = [];
|
|
386
389
|
// parse offset-table
|
|
387
390
|
for (let n = 0; n < numberOfEntries; ++n) {
|
package/lib/mp4/MP4Parser.js
CHANGED
|
@@ -6,6 +6,7 @@ import { Atom } from './Atom.js';
|
|
|
6
6
|
import * as AtomToken from './AtomToken.js';
|
|
7
7
|
import { TrackType } from '../type.js';
|
|
8
8
|
import { uint8ArrayToHex, uint8ArrayToString } from 'uint8array-extras';
|
|
9
|
+
import { Mp4ContentError } from './AtomToken.js';
|
|
9
10
|
const debug = initDebug('music-metadata:parser:MP4');
|
|
10
11
|
const tagFormat = 'iTunes';
|
|
11
12
|
const encoderDict = {
|
|
@@ -209,7 +210,7 @@ export class MP4Parser extends BasicParser {
|
|
|
209
210
|
const integerType = (signed ? 'INT' : 'UINT') + array.length * 8 + (array.length > 1 ? '_BE' : '');
|
|
210
211
|
const token = Token[integerType];
|
|
211
212
|
if (!token) {
|
|
212
|
-
throw new
|
|
213
|
+
throw new Mp4ContentError(`Token for integer type not found: "${integerType}"`);
|
|
213
214
|
}
|
|
214
215
|
return Number(token.get(array, 0));
|
|
215
216
|
}
|
|
@@ -361,7 +362,7 @@ export class MP4Parser extends BasicParser {
|
|
|
361
362
|
async parseValueAtom(tagKey, metaAtom) {
|
|
362
363
|
const dataAtom = await this.tokenizer.readToken(new AtomToken.DataAtom(Number(metaAtom.header.length) - AtomToken.Header.len));
|
|
363
364
|
if (dataAtom.type.set !== 0) {
|
|
364
|
-
throw new
|
|
365
|
+
throw new Mp4ContentError(`Unsupported type-set != 0: ${dataAtom.type.set}`);
|
|
365
366
|
}
|
|
366
367
|
// Use well-known-type table
|
|
367
368
|
// Ref: https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35
|
|
@@ -464,7 +465,7 @@ export class MP4Parser extends BasicParser {
|
|
|
464
465
|
const sampleSize = chapterTrack.sampleSize > 0 ? chapterTrack.sampleSize : chapterTrack.sampleSizeTable[i];
|
|
465
466
|
len -= nextChunkLen + sampleSize;
|
|
466
467
|
if (len < 0)
|
|
467
|
-
throw new
|
|
468
|
+
throw new Mp4ContentError('Chapter chunk exceeding token length');
|
|
468
469
|
await this.tokenizer.ignore(nextChunkLen);
|
|
469
470
|
const title = await this.tokenizer.readToken(new AtomToken.ChapterText(sampleSize));
|
|
470
471
|
debug(`Chapter ${i + 1}: ${title}`);
|
package/lib/mpeg/MpegParser.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
|
|
2
|
+
declare const MpegContentError_base: {
|
|
3
|
+
new (message: string): {
|
|
4
|
+
readonly fileType: string;
|
|
5
|
+
toString(): string;
|
|
6
|
+
name: "UnexpectedFileContentError";
|
|
7
|
+
message: string;
|
|
8
|
+
stack?: string;
|
|
9
|
+
};
|
|
10
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
11
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
12
|
+
stackTraceLimit: number;
|
|
13
|
+
};
|
|
14
|
+
export declare class MpegContentError extends MpegContentError_base {
|
|
15
|
+
}
|
|
2
16
|
export declare class MpegParser extends AbstractID3Parser {
|
|
3
17
|
private frameCount;
|
|
4
18
|
private syncFrameCount;
|
|
@@ -47,3 +61,4 @@ export declare class MpegParser extends AbstractID3Parser {
|
|
|
47
61
|
private skipFrameData;
|
|
48
62
|
private areAllSame;
|
|
49
63
|
}
|
|
64
|
+
export {};
|
package/lib/mpeg/MpegParser.js
CHANGED
|
@@ -4,7 +4,10 @@ import initDebug from 'debug';
|
|
|
4
4
|
import * as common from '../common/Util.js';
|
|
5
5
|
import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
|
|
6
6
|
import { InfoTagHeaderTag, LameEncoderVersion, readXingHeader } from './XingTag.js';
|
|
7
|
+
import { makeUnexpectedFileContentError } from '../ParseError.js';
|
|
7
8
|
const debug = initDebug('music-metadata:parser:mpeg');
|
|
9
|
+
export class MpegContentError extends makeUnexpectedFileContentError('MPEG') {
|
|
10
|
+
}
|
|
8
11
|
/**
|
|
9
12
|
* Cache buffer size used for searching synchronization preabmle
|
|
10
13
|
*/
|
|
@@ -140,13 +143,13 @@ class MpegFrameHeader {
|
|
|
140
143
|
// Calculate bitrate
|
|
141
144
|
const bitrateInKbps = this.calcBitrate();
|
|
142
145
|
if (!bitrateInKbps) {
|
|
143
|
-
throw new
|
|
146
|
+
throw new MpegContentError('Cannot determine bit-rate');
|
|
144
147
|
}
|
|
145
148
|
this.bitrate = bitrateInKbps * 1000;
|
|
146
149
|
// Calculate sampling rate
|
|
147
150
|
this.samplingRate = this.calcSamplingRate();
|
|
148
151
|
if (this.samplingRate == null) {
|
|
149
|
-
throw new
|
|
152
|
+
throw new MpegContentError('Cannot determine sampling-rate');
|
|
150
153
|
}
|
|
151
154
|
}
|
|
152
155
|
parseAdtsHeader(buf, off) {
|
|
@@ -383,7 +386,7 @@ export class MpegParser extends AbstractID3Parser {
|
|
|
383
386
|
}
|
|
384
387
|
const slot_size = header.calcSlotSize();
|
|
385
388
|
if (slot_size === null) {
|
|
386
|
-
throw new
|
|
389
|
+
throw new MpegContentError('invalid slot_size');
|
|
387
390
|
}
|
|
388
391
|
const samples_per_frame = header.calcSamplesPerFrame();
|
|
389
392
|
debug(`samples_per_frame=${samples_per_frame}`);
|
|
@@ -555,7 +558,7 @@ export class MpegParser extends AbstractID3Parser {
|
|
|
555
558
|
}
|
|
556
559
|
async skipFrameData(frameDataLeft) {
|
|
557
560
|
if (frameDataLeft < 0)
|
|
558
|
-
throw new
|
|
561
|
+
throw new MpegContentError('frame-data-left cannot be negative');
|
|
559
562
|
await this.tokenizer.ignore(frameDataLeft);
|
|
560
563
|
this.countSkipFrameData += frameDataLeft;
|
|
561
564
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare const MusepackContentError_base: {
|
|
2
|
+
new (message: string): {
|
|
3
|
+
readonly fileType: string;
|
|
4
|
+
toString(): string;
|
|
5
|
+
name: "UnexpectedFileContentError";
|
|
6
|
+
message: string;
|
|
7
|
+
stack?: string;
|
|
8
|
+
};
|
|
9
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
10
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
11
|
+
stackTraceLimit: number;
|
|
12
|
+
};
|
|
13
|
+
export declare class MusepackContentError extends MusepackContentError_base {
|
|
14
|
+
}
|
|
15
|
+
export {};
|
package/lib/musepack/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as Token from 'token-types';
|
|
|
3
3
|
import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
|
|
4
4
|
import { MpcSv8Parser } from './sv8/MpcSv8Parser.js';
|
|
5
5
|
import { MpcSv7Parser } from './sv7/MpcSv7Parser.js';
|
|
6
|
+
import { MusepackContentError } from './MusepackConentError.js';
|
|
6
7
|
const debug = initDebug('music-metadata:parser:musepack');
|
|
7
8
|
class MusepackParser extends AbstractID3Parser {
|
|
8
9
|
async postId3v2Parse() {
|
|
@@ -10,17 +11,17 @@ class MusepackParser extends AbstractID3Parser {
|
|
|
10
11
|
let mpcParser;
|
|
11
12
|
switch (signature) {
|
|
12
13
|
case 'MP+': {
|
|
13
|
-
debug('
|
|
14
|
+
debug('Stream-version 7');
|
|
14
15
|
mpcParser = new MpcSv7Parser();
|
|
15
16
|
break;
|
|
16
17
|
}
|
|
17
18
|
case 'MPC': {
|
|
18
|
-
debug('
|
|
19
|
+
debug('Stream-version 8');
|
|
19
20
|
mpcParser = new MpcSv8Parser();
|
|
20
21
|
break;
|
|
21
22
|
}
|
|
22
23
|
default: {
|
|
23
|
-
throw new
|
|
24
|
+
throw new MusepackContentError('Invalid signature prefix');
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
mpcParser.init(this.metadata, this.tokenizer, this.options);
|
|
@@ -3,6 +3,7 @@ import { BasicParser } from '../../common/BasicParser.js';
|
|
|
3
3
|
import { APEv2Parser } from '../../apev2/APEv2Parser.js';
|
|
4
4
|
import { BitReader } from './BitReader.js';
|
|
5
5
|
import * as SV7 from './StreamVersion7.js';
|
|
6
|
+
import { MusepackContentError } from '../MusepackConentError.js';
|
|
6
7
|
const debug = initDebug('music-metadata:parser:musepack');
|
|
7
8
|
export class MpcSv7Parser extends BasicParser {
|
|
8
9
|
constructor() {
|
|
@@ -14,7 +15,7 @@ export class MpcSv7Parser extends BasicParser {
|
|
|
14
15
|
async parse() {
|
|
15
16
|
const header = await this.tokenizer.readToken(SV7.Header);
|
|
16
17
|
if (header.signature !== 'MP+')
|
|
17
|
-
throw new
|
|
18
|
+
throw new MusepackContentError('Unexpected magic number');
|
|
18
19
|
debug(`stream-version=${header.streamMajorVersion}.${header.streamMinorVersion}`);
|
|
19
20
|
this.metadata.setFormat('container', 'Musepack, SV7');
|
|
20
21
|
this.metadata.setFormat('sampleRate', header.sampleFrequency);
|
|
@@ -3,6 +3,7 @@ import { BasicParser } from '../../common/BasicParser.js';
|
|
|
3
3
|
import { APEv2Parser } from '../../apev2/APEv2Parser.js';
|
|
4
4
|
import { FourCcToken } from '../../common/FourCC.js';
|
|
5
5
|
import * as SV8 from './StreamVersion8.js';
|
|
6
|
+
import { MusepackContentError } from '../MusepackConentError.js';
|
|
6
7
|
const debug = initDebug('music-metadata:parser:musepack');
|
|
7
8
|
export class MpcSv8Parser extends BasicParser {
|
|
8
9
|
constructor() {
|
|
@@ -12,7 +13,7 @@ export class MpcSv8Parser extends BasicParser {
|
|
|
12
13
|
async parse() {
|
|
13
14
|
const signature = await this.tokenizer.readToken(FourCcToken);
|
|
14
15
|
if (signature !== 'MPCK')
|
|
15
|
-
throw new
|
|
16
|
+
throw new MusepackContentError('Invalid Magic number');
|
|
16
17
|
this.metadata.setFormat('container', 'Musepack, SV8');
|
|
17
18
|
return this.parsePacket();
|
|
18
19
|
}
|
|
@@ -47,7 +48,7 @@ export class MpcSv8Parser extends BasicParser {
|
|
|
47
48
|
}
|
|
48
49
|
return APEv2Parser.tryParseApeHeader(this.metadata, this.tokenizer, this.options);
|
|
49
50
|
default:
|
|
50
|
-
throw new
|
|
51
|
+
throw new MusepackContentError(`Unexpected header: ${header.key}`);
|
|
51
52
|
}
|
|
52
53
|
} while (true);
|
|
53
54
|
}
|
package/lib/node.cjs
ADDED
package/lib/ogg/OggParser.d.ts
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { type IGetToken } from 'strtok3';
|
|
2
2
|
import { BasicParser } from '../common/BasicParser.js';
|
|
3
3
|
import type * as Ogg from './Ogg.js';
|
|
4
|
+
declare const OggContentError_base: {
|
|
5
|
+
new (message: string): {
|
|
6
|
+
readonly fileType: string;
|
|
7
|
+
toString(): string;
|
|
8
|
+
name: "UnexpectedFileContentError";
|
|
9
|
+
message: string;
|
|
10
|
+
stack?: string;
|
|
11
|
+
};
|
|
12
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
13
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
14
|
+
stackTraceLimit: number;
|
|
15
|
+
};
|
|
16
|
+
export declare class OggContentError extends OggContentError_base {
|
|
17
|
+
}
|
|
4
18
|
export declare class SegmentTable implements IGetToken<Ogg.ISegmentTable> {
|
|
5
19
|
private static sum;
|
|
6
20
|
len: number;
|
|
@@ -21,3 +35,4 @@ export declare class OggParser extends BasicParser {
|
|
|
21
35
|
*/
|
|
22
36
|
parse(): Promise<void>;
|
|
23
37
|
}
|
|
38
|
+
export {};
|
package/lib/ogg/OggParser.js
CHANGED
|
@@ -8,6 +8,9 @@ import { VorbisParser } from './vorbis/VorbisParser.js';
|
|
|
8
8
|
import { OpusParser } from './opus/OpusParser.js';
|
|
9
9
|
import { SpeexParser } from './speex/SpeexParser.js';
|
|
10
10
|
import { TheoraParser } from './theora/TheoraParser.js';
|
|
11
|
+
import { makeUnexpectedFileContentError } from '../ParseError.js';
|
|
12
|
+
export class OggContentError extends makeUnexpectedFileContentError('Ogg') {
|
|
13
|
+
}
|
|
11
14
|
const debug = initDebug('music-metadata:parser:ogg');
|
|
12
15
|
export class SegmentTable {
|
|
13
16
|
static sum(buf, off, len) {
|
|
@@ -48,7 +51,7 @@ export class OggParser extends BasicParser {
|
|
|
48
51
|
do {
|
|
49
52
|
header = await this.tokenizer.readToken(OggParser.Header);
|
|
50
53
|
if (header.capturePattern !== 'OggS')
|
|
51
|
-
throw new
|
|
54
|
+
throw new OggContentError('Invalid Ogg capture pattern');
|
|
52
55
|
this.metadata.setFormat('container', 'Ogg');
|
|
53
56
|
this.header = header;
|
|
54
57
|
this.pageNumber = header.pageSequenceNo;
|
|
@@ -78,7 +81,7 @@ export class OggParser extends BasicParser {
|
|
|
78
81
|
this.pageConsumer = new TheoraParser(this.metadata, this.options, this.tokenizer);
|
|
79
82
|
break;
|
|
80
83
|
default:
|
|
81
|
-
throw new
|
|
84
|
+
throw new OggContentError(`gg audio-codec not recognized (id=${id})`);
|
|
82
85
|
}
|
|
83
86
|
}
|
|
84
87
|
await this.pageConsumer.parsePage(header, pageData);
|
package/lib/ogg/opus/Opus.d.ts
CHANGED
|
@@ -37,6 +37,20 @@ export interface IIdHeader {
|
|
|
37
37
|
*/
|
|
38
38
|
channelMapping: number;
|
|
39
39
|
}
|
|
40
|
+
declare const OpusContentError_base: {
|
|
41
|
+
new (message: string): {
|
|
42
|
+
readonly fileType: string;
|
|
43
|
+
toString(): string;
|
|
44
|
+
name: "UnexpectedFileContentError";
|
|
45
|
+
message: string;
|
|
46
|
+
stack?: string;
|
|
47
|
+
};
|
|
48
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
49
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
50
|
+
stackTraceLimit: number;
|
|
51
|
+
};
|
|
52
|
+
export declare class OpusContentError extends OpusContentError_base {
|
|
53
|
+
}
|
|
40
54
|
/**
|
|
41
55
|
* Opus ID Header parser
|
|
42
56
|
* Ref: https://wiki.xiph.org/OggOpus#ID_Header
|
|
@@ -46,3 +60,4 @@ export declare class IdHeader implements IGetToken<IIdHeader> {
|
|
|
46
60
|
constructor(len: number);
|
|
47
61
|
get(buf: Uint8Array, off: number): IIdHeader;
|
|
48
62
|
}
|
|
63
|
+
export {};
|
package/lib/ogg/opus/Opus.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import * as Token from 'token-types';
|
|
2
|
+
import { makeUnexpectedFileContentError } from '../../ParseError.js';
|
|
3
|
+
export class OpusContentError extends makeUnexpectedFileContentError('Opus') {
|
|
4
|
+
}
|
|
2
5
|
/**
|
|
3
6
|
* Opus ID Header parser
|
|
4
7
|
* Ref: https://wiki.xiph.org/OggOpus#ID_Header
|
|
@@ -7,7 +10,7 @@ export class IdHeader {
|
|
|
7
10
|
constructor(len) {
|
|
8
11
|
this.len = len;
|
|
9
12
|
if (len < 19) {
|
|
10
|
-
throw new
|
|
13
|
+
throw new OpusContentError('ID-header-page 0 should be at least 19 bytes long');
|
|
11
14
|
}
|
|
12
15
|
}
|
|
13
16
|
get(buf, off) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as Token from 'token-types';
|
|
2
2
|
import { VorbisParser } from '../vorbis/VorbisParser.js';
|
|
3
3
|
import * as Opus from './Opus.js';
|
|
4
|
+
import { OpusContentError } from './Opus.js';
|
|
4
5
|
/**
|
|
5
6
|
* Opus parser
|
|
6
7
|
* Internet Engineering Task Force (IETF) - RFC 6716
|
|
@@ -23,7 +24,7 @@ export class OpusParser extends VorbisParser {
|
|
|
23
24
|
// Parse Opus ID Header
|
|
24
25
|
this.idHeader = new Opus.IdHeader(pageData.length).get(pageData, 0);
|
|
25
26
|
if (this.idHeader.magicSignature !== "OpusHead")
|
|
26
|
-
throw new
|
|
27
|
+
throw new OpusContentError("Illegal ogg/Opus magic-signature");
|
|
27
28
|
this.metadata.setFormat('sampleRate', this.idHeader.inputSampleRate);
|
|
28
29
|
this.metadata.setFormat('numberOfChannels', this.idHeader.channelCount);
|
|
29
30
|
}
|
|
@@ -2,6 +2,20 @@ import { type IVorbisPicture } from './Vorbis.js';
|
|
|
2
2
|
import type { IPageConsumer, IPageHeader } from '../Ogg.js';
|
|
3
3
|
import type { IOptions } from '../../type.js';
|
|
4
4
|
import type { INativeMetadataCollector } from '../../common/MetadataCollector.js';
|
|
5
|
+
declare const VorbisContentError_base: {
|
|
6
|
+
new (message: string): {
|
|
7
|
+
readonly fileType: string;
|
|
8
|
+
toString(): string;
|
|
9
|
+
name: "UnexpectedFileContentError";
|
|
10
|
+
message: string;
|
|
11
|
+
stack?: string;
|
|
12
|
+
};
|
|
13
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
14
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
15
|
+
stackTraceLimit: number;
|
|
16
|
+
};
|
|
17
|
+
export declare class VorbisContentError extends VorbisContentError_base {
|
|
18
|
+
}
|
|
5
19
|
/**
|
|
6
20
|
* Vorbis 1 Parser.
|
|
7
21
|
* Used by OggParser
|
|
@@ -34,3 +48,4 @@ export declare class VorbisParser implements IPageConsumer {
|
|
|
34
48
|
*/
|
|
35
49
|
protected parseUserCommentList(pageData: Uint8Array, offset: number): Promise<void>;
|
|
36
50
|
}
|
|
51
|
+
export {};
|
|
@@ -2,7 +2,10 @@ import * as Token from 'token-types';
|
|
|
2
2
|
import debugInit from 'debug';
|
|
3
3
|
import { VorbisDecoder } from './VorbisDecoder.js';
|
|
4
4
|
import { CommonHeader, IdentificationHeader, VorbisPictureToken } from './Vorbis.js';
|
|
5
|
+
import { makeUnexpectedFileContentError } from '../../ParseError.js';
|
|
5
6
|
const debug = debugInit('music-metadata:parser:ogg:vorbis1');
|
|
7
|
+
export class VorbisContentError extends makeUnexpectedFileContentError('Vorbis') {
|
|
8
|
+
}
|
|
6
9
|
/**
|
|
7
10
|
* Vorbis 1 Parser.
|
|
8
11
|
* Used by OggParser
|
|
@@ -25,7 +28,7 @@ export class VorbisParser {
|
|
|
25
28
|
else {
|
|
26
29
|
if (header.headerType.continued) {
|
|
27
30
|
if (this.pageSegments.length === 0) {
|
|
28
|
-
throw new
|
|
31
|
+
throw new VorbisContentError('Cannot continue on previous page');
|
|
29
32
|
}
|
|
30
33
|
this.pageSegments.push(pageData);
|
|
31
34
|
}
|
|
@@ -93,7 +96,7 @@ export class VorbisParser {
|
|
|
93
96
|
// Parse Vorbis common header
|
|
94
97
|
const commonHeader = CommonHeader.get(pageData, 0);
|
|
95
98
|
if (commonHeader.vorbis !== 'vorbis')
|
|
96
|
-
throw new
|
|
99
|
+
throw new VorbisContentError('Metadata does not look like Vorbis');
|
|
97
100
|
if (commonHeader.packetType === 1) {
|
|
98
101
|
const idHeader = IdentificationHeader.get(pageData, CommonHeader.len);
|
|
99
102
|
this.metadata.setFormat('sampleRate', idHeader.sampleRate);
|
|
@@ -102,7 +105,7 @@ export class VorbisParser {
|
|
|
102
105
|
debug('sample-rate=%s[hz], bitrate=%s[b/s], channel-mode=%s', idHeader.sampleRate, idHeader.bitrateNominal, idHeader.channelMode);
|
|
103
106
|
}
|
|
104
107
|
else
|
|
105
|
-
throw new
|
|
108
|
+
throw new VorbisContentError('First Ogg page should be type 1: the identification header');
|
|
106
109
|
}
|
|
107
110
|
async parseFullPage(pageData) {
|
|
108
111
|
// New page
|
package/lib/wav/WaveChunk.d.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import type { IGetToken } from 'strtok3';
|
|
2
2
|
import type { IChunkHeader } from '../iff/index.js';
|
|
3
|
+
declare const WaveContentError_base: {
|
|
4
|
+
new (message: string): {
|
|
5
|
+
readonly fileType: string;
|
|
6
|
+
toString(): string;
|
|
7
|
+
name: "UnexpectedFileContentError";
|
|
8
|
+
message: string;
|
|
9
|
+
stack?: string;
|
|
10
|
+
};
|
|
11
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
12
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
13
|
+
stackTraceLimit: number;
|
|
14
|
+
};
|
|
15
|
+
export declare class WaveContentError extends WaveContentError_base {
|
|
16
|
+
}
|
|
3
17
|
/**
|
|
4
18
|
* Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317599(v=vs.85).aspx
|
|
5
19
|
*/
|
|
@@ -61,3 +75,4 @@ export declare class FactChunk implements IGetToken<IFactChunk> {
|
|
|
61
75
|
constructor(header: IChunkHeader);
|
|
62
76
|
get(buf: Uint8Array, off: number): IFactChunk;
|
|
63
77
|
}
|
|
78
|
+
export {};
|
package/lib/wav/WaveChunk.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import * as Token from 'token-types';
|
|
2
|
+
import { makeUnexpectedFileContentError } from '../ParseError.js';
|
|
3
|
+
export class WaveContentError extends makeUnexpectedFileContentError('Wave') {
|
|
4
|
+
}
|
|
2
5
|
/**
|
|
3
6
|
* Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317599(v=vs.85).aspx
|
|
4
7
|
*/
|
|
@@ -27,7 +30,7 @@ export var WaveFormat;
|
|
|
27
30
|
export class Format {
|
|
28
31
|
constructor(header) {
|
|
29
32
|
if (header.chunkSize < 16)
|
|
30
|
-
throw new
|
|
33
|
+
throw new WaveContentError('Invalid chunk size');
|
|
31
34
|
this.len = header.chunkSize;
|
|
32
35
|
}
|
|
33
36
|
get(buf, off) {
|
|
@@ -49,7 +52,7 @@ export class Format {
|
|
|
49
52
|
export class FactChunk {
|
|
50
53
|
constructor(header) {
|
|
51
54
|
if (header.chunkSize < 4) {
|
|
52
|
-
throw new
|
|
55
|
+
throw new WaveContentError('Invalid fact chunk size.');
|
|
53
56
|
}
|
|
54
57
|
this.len = header.chunkSize;
|
|
55
58
|
}
|