music-metadata 10.2.0 → 10.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +435 -126
  2. package/lib/ParseError.d.ts +87 -0
  3. package/lib/ParseError.js +39 -0
  4. package/lib/ParserFactory.d.ts +1 -1
  5. package/lib/ParserFactory.js +8 -7
  6. package/lib/aiff/AiffParser.js +4 -4
  7. package/lib/aiff/AiffToken.d.ts +15 -0
  8. package/lib/aiff/AiffToken.js +5 -2
  9. package/lib/apev2/APEv2Parser.d.ts +15 -0
  10. package/lib/apev2/APEv2Parser.js +6 -3
  11. package/lib/asf/AsfObject.d.ts +15 -0
  12. package/lib/asf/AsfObject.js +4 -1
  13. package/lib/asf/AsfParser.js +2 -1
  14. package/lib/common/CombinedTagMapper.js +2 -1
  15. package/lib/common/FourCC.js +3 -2
  16. package/lib/common/Util.js +3 -2
  17. package/lib/core.d.ts +3 -1
  18. package/lib/core.js +1 -1
  19. package/lib/default.cjs +5 -0
  20. package/lib/dsdiff/DsdiffParser.d.ts +15 -0
  21. package/lib/dsdiff/DsdiffParser.js +6 -3
  22. package/lib/dsf/DsfParser.d.ts +15 -0
  23. package/lib/dsf/DsfParser.js +4 -1
  24. package/lib/ebml/EbmlIterator.d.ts +15 -0
  25. package/lib/ebml/EbmlIterator.js +5 -2
  26. package/lib/flac/FlacParser.js +5 -2
  27. package/lib/id3v2/FrameParser.d.ts +14 -0
  28. package/lib/id3v2/FrameParser.js +7 -1
  29. package/lib/id3v2/ID3v2Parser.js +8 -5
  30. package/lib/mp4/AtomToken.d.ts +14 -0
  31. package/lib/mp4/AtomToken.js +6 -3
  32. package/lib/mp4/MP4Parser.js +4 -3
  33. package/lib/mpeg/MpegParser.d.ts +15 -0
  34. package/lib/mpeg/MpegParser.js +7 -4
  35. package/lib/musepack/MusepackConentError.d.ts +15 -0
  36. package/lib/musepack/MusepackConentError.js +4 -0
  37. package/lib/musepack/index.js +4 -3
  38. package/lib/musepack/sv7/MpcSv7Parser.js +2 -1
  39. package/lib/musepack/sv8/MpcSv8Parser.js +3 -2
  40. package/lib/node.cjs +5 -0
  41. package/lib/ogg/OggParser.d.ts +15 -0
  42. package/lib/ogg/OggParser.js +5 -2
  43. package/lib/ogg/opus/Opus.d.ts +15 -0
  44. package/lib/ogg/opus/Opus.js +4 -1
  45. package/lib/ogg/opus/OpusParser.js +2 -1
  46. package/lib/ogg/vorbis/VorbisParser.d.ts +15 -0
  47. package/lib/ogg/vorbis/VorbisParser.js +6 -3
  48. package/lib/wav/WaveChunk.d.ts +15 -0
  49. package/lib/wav/WaveChunk.js +5 -2
  50. package/lib/wav/WaveParser.js +3 -2
  51. package/lib/wavpack/WavPackParser.d.ts +15 -0
  52. package/lib/wavpack/WavPackParser.js +6 -3
  53. package/package.json +16 -7
@@ -0,0 +1,87 @@
1
+ export type UnionOfParseErrors = CouldNotDetermineFileTypeError | UnsupportedFileTypeError | UnexpectedFileContentError | FieldDecodingError | InternalParserError;
2
+ export declare const makeParseError: <Name extends string>(name: Name) => {
3
+ new (message: string): {
4
+ name: Name;
5
+ message: string;
6
+ stack?: string;
7
+ };
8
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
9
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
10
+ stackTraceLimit: number;
11
+ };
12
+ declare const CouldNotDetermineFileTypeError_base: {
13
+ new (message: string): {
14
+ name: "CouldNotDetermineFileTypeError";
15
+ message: string;
16
+ stack?: string;
17
+ };
18
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
19
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
20
+ stackTraceLimit: number;
21
+ };
22
+ export declare class CouldNotDetermineFileTypeError extends CouldNotDetermineFileTypeError_base {
23
+ }
24
+ declare const UnsupportedFileTypeError_base: {
25
+ new (message: string): {
26
+ name: "UnsupportedFileTypeError";
27
+ message: string;
28
+ stack?: string;
29
+ };
30
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
31
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
32
+ stackTraceLimit: number;
33
+ };
34
+ export declare class UnsupportedFileTypeError extends UnsupportedFileTypeError_base {
35
+ }
36
+ declare const UnexpectedFileContentError_base: {
37
+ new (message: string): {
38
+ name: "UnexpectedFileContentError";
39
+ message: string;
40
+ stack?: string;
41
+ };
42
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
43
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
44
+ stackTraceLimit: number;
45
+ };
46
+ declare class UnexpectedFileContentError extends UnexpectedFileContentError_base {
47
+ readonly fileType: string;
48
+ constructor(fileType: string, message: string);
49
+ toString(): string;
50
+ }
51
+ declare const FieldDecodingError_base: {
52
+ new (message: string): {
53
+ name: "FieldDecodingError";
54
+ message: string;
55
+ stack?: string;
56
+ };
57
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
58
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
59
+ stackTraceLimit: number;
60
+ };
61
+ export declare class FieldDecodingError extends FieldDecodingError_base {
62
+ }
63
+ declare const InternalParserError_base: {
64
+ new (message: string): {
65
+ name: "InternalParserError";
66
+ message: string;
67
+ stack?: string;
68
+ };
69
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
70
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
71
+ stackTraceLimit: number;
72
+ };
73
+ export declare class InternalParserError extends InternalParserError_base {
74
+ }
75
+ export declare const makeUnexpectedFileContentError: <FileType extends string>(fileType: FileType) => {
76
+ new (message: string): {
77
+ readonly fileType: string;
78
+ toString(): string;
79
+ name: "UnexpectedFileContentError";
80
+ message: string;
81
+ stack?: string;
82
+ };
83
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
84
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
85
+ stackTraceLimit: number;
86
+ };
87
+ export {};
@@ -0,0 +1,39 @@
1
+ export const makeParseError = (name) => {
2
+ return class ParseError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = name;
6
+ }
7
+ };
8
+ };
9
+ // Concrete error class representing a file type determination failure.
10
+ export class CouldNotDetermineFileTypeError extends makeParseError('CouldNotDetermineFileTypeError') {
11
+ }
12
+ // Concrete error class representing an unsupported file type.
13
+ export class UnsupportedFileTypeError extends makeParseError('UnsupportedFileTypeError') {
14
+ }
15
+ // Concrete error class representing unexpected file content.
16
+ class UnexpectedFileContentError extends makeParseError('UnexpectedFileContentError') {
17
+ constructor(fileType, message) {
18
+ super(message);
19
+ this.fileType = fileType;
20
+ }
21
+ // Override toString to include file type information.
22
+ toString() {
23
+ return `${this.name} (FileType: ${this.fileType}): ${this.message}`;
24
+ }
25
+ }
26
+ // Concrete error class representing a field decoding error.
27
+ export class FieldDecodingError extends makeParseError('FieldDecodingError') {
28
+ }
29
+ export class InternalParserError extends makeParseError('InternalParserError') {
30
+ }
31
+ // Factory function to create a specific type of UnexpectedFileContentError.
32
+ export const makeUnexpectedFileContentError = (fileType) => {
33
+ return class extends UnexpectedFileContentError {
34
+ constructor(message) {
35
+ super(fileType, message);
36
+ }
37
+ };
38
+ };
39
+ //# sourceMappingURL=ParseError.js.map
@@ -1,6 +1,6 @@
1
1
  import { type MediaType } from 'media-typer';
2
2
  import { type INativeMetadataCollector } from './common/MetadataCollector.js';
3
- import type { IOptions, IAudioMetadata, ParserType } from './type.js';
3
+ import type { IAudioMetadata, IOptions, ParserType } from './type.js';
4
4
  import type { ITokenizer } from 'strtok3';
5
5
  export interface ITokenParser {
6
6
  /**
@@ -16,6 +16,7 @@ import { WavPackParser } from './wavpack/WavPackParser.js';
16
16
  import { DsfParser } from './dsf/DsfParser.js';
17
17
  import { DsdiffParser } from './dsdiff/DsdiffParser.js';
18
18
  import { MatroskaParser } from './matroska/MatroskaParser.js';
19
+ import { CouldNotDetermineFileTypeError, InternalParserError, UnsupportedFileTypeError } from './ParseError.js';
19
20
  const debug = initDebug('music-metadata:parser:factory');
20
21
  export function parseHttpContentType(contentType) {
21
22
  const type = ContentType.parse(contentType);
@@ -44,22 +45,22 @@ export async function parseOnContentType(tokenizer, opts) {
44
45
  }
45
46
  export async function parse(tokenizer, parserId, opts) {
46
47
  if (!parserId) {
47
- // Parser could not be determined on MIME-type or extension
48
- debug('Guess parser on content...');
49
- const buf = new Uint8Array(4100);
50
- await tokenizer.peekBuffer(buf, { mayBeLess: true });
51
48
  if (tokenizer.fileInfo.path) {
52
49
  parserId = getParserIdForExtension(tokenizer.fileInfo.path);
53
50
  }
54
51
  if (!parserId) {
52
+ // Parser could not be determined on MIME-type or extension
53
+ debug('Guess parser on content...');
54
+ const buf = new Uint8Array(4100);
55
+ await tokenizer.peekBuffer(buf, { mayBeLess: true });
55
56
  const guessedType = await fileTypeFromBuffer(buf);
56
57
  if (!guessedType) {
57
- throw new Error('Failed to determine audio format');
58
+ throw new CouldNotDetermineFileTypeError('Failed to determine audio format');
58
59
  }
59
60
  debug(`Guessed file type is mime=${guessedType.mime}, extension=${guessedType.ext}`);
60
61
  parserId = getParserIdForMimeType(guessedType.mime);
61
62
  if (!parserId) {
62
- throw new Error(`Guessed MIME-type not supported: ${guessedType.mime}`);
63
+ throw new UnsupportedFileTypeError(`Guessed MIME-type not supported: ${guessedType.mime}`);
63
64
  }
64
65
  }
65
66
  }
@@ -149,7 +150,7 @@ export async function loadParser(moduleName) {
149
150
  case 'wavpack': return new WavPackParser();
150
151
  case 'matroska': return new MatroskaParser();
151
152
  default:
152
- throw new Error(`Unknown parser type: ${moduleName}`);
153
+ throw new InternalParserError(`Unknown parser type: ${moduleName}`);
153
154
  }
154
155
  }
155
156
  function getExtension(fname) {
@@ -5,8 +5,8 @@ import { ID3v2Parser } from '../id3v2/ID3v2Parser.js';
5
5
  import { FourCcToken } from '../common/FourCC.js';
6
6
  import { BasicParser } from '../common/BasicParser.js';
7
7
  import * as AiffToken from './AiffToken.js';
8
+ import { AiffContentError, compressionTypes } from './AiffToken.js';
8
9
  import * as iff from '../iff/index.js';
9
- import { compressionTypes } from './AiffToken.js';
10
10
  const debug = initDebug('music-metadata:parser:aiff');
11
11
  /**
12
12
  * AIFF - Audio Interchange File Format
@@ -23,7 +23,7 @@ export class AIFFParser extends BasicParser {
23
23
  async parse() {
24
24
  const header = await this.tokenizer.readToken(iff.Header);
25
25
  if (header.chunkID !== 'FORM')
26
- throw new Error('Invalid Chunk-ID, expected \'FORM\''); // Not AIFF format
26
+ throw new AiffContentError('Invalid Chunk-ID, expected \'FORM\''); // Not AIFF format
27
27
  const type = await this.tokenizer.readToken(FourCcToken);
28
28
  switch (type) {
29
29
  case 'AIFF':
@@ -35,7 +35,7 @@ export class AIFFParser extends BasicParser {
35
35
  this.isCompressed = true;
36
36
  break;
37
37
  default:
38
- throw new Error(`Unsupported AIFF type: ${type}`);
38
+ throw new AiffContentError(`Unsupported AIFF type: ${type}`);
39
39
  }
40
40
  this.metadata.setFormat('lossless', !this.isCompressed);
41
41
  try {
@@ -60,7 +60,7 @@ export class AIFFParser extends BasicParser {
60
60
  switch (header.chunkID) {
61
61
  case 'COMM': { // The Common Chunk
62
62
  if (this.isCompressed === null) {
63
- throw new Error('Failed to parse AIFF.COMM chunk when compression type is unknown');
63
+ throw new AiffContentError('Failed to parse AIFF.COMM chunk when compression type is unknown');
64
64
  }
65
65
  const common = await this.tokenizer.readToken(new AiffToken.Common(header, this.isCompressed));
66
66
  this.metadata.setFormat('bitsPerSample', common.sampleSize);
@@ -12,6 +12,20 @@ export declare const compressionTypes: {
12
12
  FL32: string;
13
13
  };
14
14
  export type CompressionTypeCode = keyof typeof compressionTypes;
15
+ declare const AiffContentError_base: {
16
+ new (message: string): {
17
+ readonly fileType: string;
18
+ toString(): string;
19
+ name: "UnexpectedFileContentError";
20
+ message: string;
21
+ stack?: string;
22
+ };
23
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
24
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
25
+ stackTraceLimit: number;
26
+ };
27
+ export declare class AiffContentError extends AiffContentError_base {
28
+ }
15
29
  /**
16
30
  * The Common Chunk.
17
31
  * Describes fundamental parameters of the waveform data such as sample rate, bit resolution, and how many channels of
@@ -31,3 +45,4 @@ export declare class Common implements IGetToken<ICommon> {
31
45
  constructor(header: iff.IChunkHeader, isAifc: boolean);
32
46
  get(buf: Uint8Array, off: number): ICommon;
33
47
  }
48
+ export {};
@@ -1,5 +1,6 @@
1
1
  import * as Token from 'token-types';
2
2
  import { FourCcToken } from '../common/FourCC.js';
3
+ import { makeUnexpectedFileContentError } from '../ParseError.js';
3
4
  export const compressionTypes = {
4
5
  NONE: 'not compressed PCM Apple Computer',
5
6
  sowt: 'PCM (byte swapped)',
@@ -11,12 +12,14 @@ export const compressionTypes = {
11
12
  ALAW: 'CCITT G.711 A-law 8-bit ITU-T G.711 A-law',
12
13
  FL32: 'Float 32 IEEE 32-bit float '
13
14
  };
15
+ export class AiffContentError extends makeUnexpectedFileContentError('AIFF') {
16
+ }
14
17
  export class Common {
15
18
  constructor(header, isAifc) {
16
19
  this.isAifc = isAifc;
17
20
  const minimumChunkSize = isAifc ? 22 : 18;
18
21
  if (header.chunkSize < minimumChunkSize)
19
- throw new Error(`COMMON CHUNK size should always be at least ${minimumChunkSize}`);
22
+ throw new AiffContentError(`COMMON CHUNK size should always be at least ${minimumChunkSize}`);
20
23
  this.len = header.chunkSize;
21
24
  }
22
25
  get(buf, off) {
@@ -39,7 +42,7 @@ export class Common {
39
42
  res.compressionName = new Token.StringType(strLen, 'latin1').get(buf, off + 23);
40
43
  }
41
44
  else {
42
- throw new Error('Illegal pstring length');
45
+ throw new AiffContentError('Illegal pstring length');
43
46
  }
44
47
  }
45
48
  else {
@@ -3,6 +3,20 @@ import type { IOptions, IRandomReader, IApeHeader } from '../type.js';
3
3
  import type { INativeMetadataCollector } from '../common/MetadataCollector.js';
4
4
  import { BasicParser } from '../common/BasicParser.js';
5
5
  import { type IFooter, type IHeader } from './APEv2Token.js';
6
+ declare const ApeContentError_base: {
7
+ new (message: string): {
8
+ readonly fileType: string;
9
+ toString(): string;
10
+ name: "UnexpectedFileContentError";
11
+ message: string;
12
+ stack?: string;
13
+ };
14
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
15
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
16
+ stackTraceLimit: number;
17
+ };
18
+ export declare class ApeContentError extends ApeContentError_base {
19
+ }
6
20
  export declare class APEv2Parser extends BasicParser {
7
21
  static tryParseApeHeader(metadata: INativeMetadataCollector, tokenizer: strtok3.ITokenizer, options: IOptions): Promise<void>;
8
22
  /**
@@ -28,3 +42,4 @@ export declare class APEv2Parser extends BasicParser {
28
42
  private parseDescriptorExpansion;
29
43
  private parseHeader;
30
44
  }
45
+ export {};
@@ -5,9 +5,12 @@ import { uint8ArrayToString } from 'uint8array-extras';
5
5
  import * as util from '../common/Util.js';
6
6
  import { BasicParser } from '../common/BasicParser.js';
7
7
  import { DataType, DescriptorParser, Header, TagFooter, TagItemHeader } from './APEv2Token.js';
8
+ import { makeUnexpectedFileContentError } from '../ParseError.js';
8
9
  const debug = initDebug('music-metadata:parser:APEv2');
9
10
  const tagFormat = 'APEv2';
10
11
  const preamble = 'APETAGEX';
12
+ export class ApeContentError extends makeUnexpectedFileContentError('APEv2') {
13
+ }
11
14
  export class APEv2Parser extends BasicParser {
12
15
  constructor() {
13
16
  super(...arguments);
@@ -52,7 +55,7 @@ export class APEv2Parser extends BasicParser {
52
55
  static parseTagFooter(metadata, buffer, options) {
53
56
  const footer = TagFooter.get(buffer, buffer.length - TagFooter.len);
54
57
  if (footer.ID !== preamble)
55
- throw new Error('Unexpected APEv2 Footer ID preamble value.');
58
+ throw new ApeContentError('Unexpected APEv2 Footer ID preamble value');
56
59
  strtok3.fromBuffer(buffer);
57
60
  const apeParser = new APEv2Parser();
58
61
  apeParser.init(metadata, strtok3.fromBuffer(buffer), options);
@@ -83,7 +86,7 @@ export class APEv2Parser extends BasicParser {
83
86
  async parse() {
84
87
  const descriptor = await this.tokenizer.readToken(DescriptorParser);
85
88
  if (descriptor.ID !== 'MAC ')
86
- throw new Error('Unexpected descriptor ID');
89
+ throw new ApeContentError('Unexpected descriptor ID');
87
90
  this.ape.descriptor = descriptor;
88
91
  const lenExp = descriptor.descriptorBytes - DescriptorParser.len;
89
92
  const header = await (lenExp > 0 ? this.parseDescriptorExpansion(lenExp) : this.parseHeader());
@@ -156,7 +159,7 @@ export class APEv2Parser extends BasicParser {
156
159
  this.metadata.setFormat('numberOfChannels', header.channel);
157
160
  this.metadata.setFormat('duration', APEv2Parser.calculateDuration(header));
158
161
  if (!this.ape.descriptor) {
159
- throw new Error('Missing APE descriptor');
162
+ throw new ApeContentError('Missing APE descriptor');
160
163
  }
161
164
  return {
162
165
  forwardBytes: this.ape.descriptor.seekTableBytes + this.ape.descriptor.headerDataBytes +
@@ -1,6 +1,20 @@
1
1
  import type { IGetToken, ITokenizer } from 'strtok3';
2
2
  import type { AnyTagValue, IPicture, ITag } from '../type.js';
3
3
  import GUID from './GUID.js';
4
+ declare const AsfContentParseError_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 AsfContentParseError extends AsfContentParseError_base {
17
+ }
4
18
  /**
5
19
  * Data Type: Specifies the type of information being stored. The following values are recognized.
6
20
  */
@@ -307,3 +321,4 @@ export declare class WmPictureToken implements IGetToken<IWmPicture> {
307
321
  constructor(len: number);
308
322
  get(buffer: Uint8Array, offset: number): IWmPicture;
309
323
  }
324
+ export {};
@@ -4,6 +4,9 @@ import * as util from '../common/Util.js';
4
4
  import GUID from './GUID.js';
5
5
  import { getParserForAttr, parseUnicodeAttr } from './AsfUtil.js';
6
6
  import { AttachedPictureType } from '../id3v2/ID3v2Token.js';
7
+ import { makeUnexpectedFileContentError } from '../ParseError.js';
8
+ export class AsfContentParseError extends makeUnexpectedFileContentError('ASF') {
9
+ }
7
10
  /**
8
11
  * Data Type: Specifies the type of information being stored. The following values are recognized.
9
12
  */
@@ -73,7 +76,7 @@ export class State {
73
76
  else {
74
77
  const parseAttr = getParserForAttr(valueType);
75
78
  if (!parseAttr) {
76
- throw new Error(`unexpected value headerType: ${valueType}`);
79
+ throw new AsfContentParseError(`unexpected value headerType: ${valueType}`);
77
80
  }
78
81
  tags.push({ id: name, value: parseAttr(data) });
79
82
  }
@@ -3,6 +3,7 @@ import { TrackType } from '../type.js';
3
3
  import GUID from './GUID.js';
4
4
  import * as AsfObject from './AsfObject.js';
5
5
  import { BasicParser } from '../common/BasicParser.js';
6
+ import { AsfContentParseError } from './AsfObject.js';
6
7
  const debug = initDebug('music-metadata:parser:ASF');
7
8
  const headerType = 'asf';
8
9
  /**
@@ -19,7 +20,7 @@ export class AsfParser extends BasicParser {
19
20
  async parse() {
20
21
  const header = await this.tokenizer.readToken(AsfObject.TopLevelHeaderObjectToken);
21
22
  if (!header.objectId.equals(GUID.HeaderObject)) {
22
- throw new Error(`expected asf header; but was not found; got: ${header.objectId.str}`);
23
+ throw new AsfContentParseError(`expected asf header; but was not found; got: ${header.objectId.str}`);
23
24
  }
24
25
  try {
25
26
  await this.parseObjectHeader(header.numberOfHeaderObjects);
@@ -8,6 +8,7 @@ import { VorbisTagMapper } from '../ogg/vorbis/VorbisTagMapper.js';
8
8
  import { RiffInfoTagMapper } from '../riff/RiffInfoTagMap.js';
9
9
  import { MatroskaTagMapper } from '../matroska/MatroskaTagMapper.js';
10
10
  import { AiffTagMapper } from '../aiff/AiffTagMap.js';
11
+ import { InternalParserError } from '../ParseError.js';
11
12
  export class CombinedTagMapper {
12
13
  constructor() {
13
14
  this.tagMappers = {};
@@ -39,7 +40,7 @@ export class CombinedTagMapper {
39
40
  if (tagMapper) {
40
41
  return this.tagMappers[tagType].mapGenericTag(tag, warnings);
41
42
  }
42
- throw new Error(`No generic tag mapper defined for tag-format: ${tagType}`);
43
+ throw new InternalParserError(`No generic tag mapper defined for tag-format: ${tagType}`);
43
44
  }
44
45
  registerTagMapper(genericTagMapper) {
45
46
  for (const tagType of genericTagMapper.tagTypes) {
@@ -1,5 +1,6 @@
1
1
  import { stringToUint8Array, uint8ArrayToString } from 'uint8array-extras';
2
2
  import * as util from './Util.js';
3
+ import { InternalParserError, FieldDecodingError } from '../ParseError.js';
3
4
  const validFourCC = /^[\x21-\x7e©][\x20-\x7e\x00()]{3}/;
4
5
  /**
5
6
  * Token for read FourCC
@@ -10,14 +11,14 @@ export const FourCcToken = {
10
11
  get: (buf, off) => {
11
12
  const id = uint8ArrayToString(buf.slice(off, off + FourCcToken.len), 'latin1');
12
13
  if (!id.match(validFourCC)) {
13
- throw new Error(`FourCC contains invalid characters: ${util.a2hex(id)} "${id}"`);
14
+ throw new FieldDecodingError(`FourCC contains invalid characters: ${util.a2hex(id)} "${id}"`);
14
15
  }
15
16
  return id;
16
17
  },
17
18
  put: (buffer, offset, id) => {
18
19
  const str = stringToUint8Array(id);
19
20
  if (str.length !== 4)
20
- throw new Error('Invalid length');
21
+ throw new InternalParserError('Invalid length');
21
22
  buffer.set(str, offset);
22
23
  return offset + 4;
23
24
  }
@@ -1,4 +1,5 @@
1
1
  import { StringType } from 'token-types';
2
+ import { FieldDecodingError } from '../ParseError.js';
2
3
  export function getBit(buf, off, bit) {
3
4
  return (buf[off] & (1 << bit)) !== 0;
4
5
  }
@@ -34,7 +35,7 @@ export function trimRightNull(x) {
34
35
  function swapBytes(uint8Array) {
35
36
  const l = uint8Array.length;
36
37
  if ((l & 1) !== 0)
37
- throw new Error('Buffer length must be even');
38
+ throw new FieldDecodingError('Buffer length must be even');
38
39
  for (let i = 0; i < l; i += 2) {
39
40
  const a = uint8Array[i];
40
41
  uint8Array[i] = uint8Array[i + 1];
@@ -54,7 +55,7 @@ export function decodeString(uint8Array, encoding) {
54
55
  if (encoding === 'utf-16le' && uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) {
55
56
  // BOM, indicating big endian decoding
56
57
  if ((uint8Array.length & 1) !== 0)
57
- throw new Error('Expected even number of octets for 16-bit unicode string');
58
+ throw new FieldDecodingError('Expected even number of octets for 16-bit unicode string');
58
59
  return decodeString(swapBytes(uint8Array), encoding);
59
60
  }
60
61
  return new StringType(uint8Array.length, encoding).get(uint8Array, 0);
package/lib/core.d.ts CHANGED
@@ -5,6 +5,7 @@ import { type AnyWebByteStream, type IFileInfo, type ITokenizer } from 'strtok3'
5
5
  import type { IAudioMetadata, INativeTagDict, IOptions, IPicture, IPrivateOptions, IRandomReader, ITag } from './type.js';
6
6
  export type { IFileInfo } from 'strtok3';
7
7
  export { type IAudioMetadata, type IOptions, type ITag, type INativeTagDict, type ICommonTagsResult, type IFormat, type IPicture, type IRatio, type IChapter, type ILyricsTag, LyricsContentType, TimestampFormat, IMetadataEventTag, IMetadataEvent } from './type.js';
8
+ export type * from './ParseError.js';
8
9
  /**
9
10
  * Parse Web API File
10
11
  * Requires Blob to be able to stream using a ReadableStreamBYOBReader, only available since Node.js ≥ 20
@@ -22,7 +23,7 @@ export declare function parseBlob(blob: Blob, options?: IOptions): Promise<IAudi
22
23
  */
23
24
  export declare function parseWebStream(webStream: AnyWebByteStream, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
24
25
  /**
25
- * Parse audio from Node Buffer
26
+ * Parse audio from memory
26
27
  * @param uint8Array - Uint8Array holding audio data
27
28
  * @param fileInfo - File information object or MIME-type string
28
29
  * @param options - Parsing options
@@ -56,3 +57,4 @@ export declare function ratingToStars(rating: number | undefined): number;
56
57
  */
57
58
  export declare function selectCover(pictures?: IPicture[]): IPicture | null;
58
59
  export declare function scanAppendingHeaders(randomReader: IRandomReader, options?: IPrivateOptions): Promise<void>;
60
+ export declare function loadMusicMetadata(): Promise<typeof import('music-metadata')>;
package/lib/core.js CHANGED
@@ -33,7 +33,7 @@ export function parseWebStream(webStream, fileInfo, options = {}) {
33
33
  return parseFromTokenizer(fromWebStream(webStream, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo }), options);
34
34
  }
35
35
  /**
36
- * Parse audio from Node Buffer
36
+ * Parse audio from memory
37
37
  * @param uint8Array - Uint8Array holding audio data
38
38
  * @param fileInfo - File information object or MIME-type string
39
39
  * @param options - Parsing options
@@ -0,0 +1,5 @@
1
+ // CommonJS core (default) entry point
2
+ "use strict";
3
+ module.exports = {
4
+ loadMusicMetadata: () => import('./core.js'),
5
+ };
@@ -1,4 +1,18 @@
1
1
  import { BasicParser } from '../common/BasicParser.js';
2
+ declare const DsdiffContentParseError_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 DsdiffContentParseError extends DsdiffContentParseError_base {
15
+ }
2
16
  /**
3
17
  * DSDIFF - Direct Stream Digital Interchange File Format (Phillips)
4
18
  *
@@ -12,3 +26,4 @@ export declare class DsdiffParser extends BasicParser {
12
26
  private handleSoundPropertyChunks;
13
27
  private handleChannelChunks;
14
28
  }
29
+ export {};
@@ -5,7 +5,10 @@ import { FourCcToken } from '../common/FourCC.js';
5
5
  import { BasicParser } from '../common/BasicParser.js';
6
6
  import { ID3v2Parser } from '../id3v2/ID3v2Parser.js';
7
7
  import { ChunkHeader64 } from './DsdiffToken.js';
8
+ import { makeUnexpectedFileContentError } from '../ParseError.js';
8
9
  const debug = initDebug('music-metadata:parser:aiff');
10
+ export class DsdiffContentParseError extends makeUnexpectedFileContentError('DSDIFF') {
11
+ }
9
12
  /**
10
13
  * DSDIFF - Direct Stream Digital Interchange File Format (Phillips)
11
14
  *
@@ -16,7 +19,7 @@ export class DsdiffParser extends BasicParser {
16
19
  async parse() {
17
20
  const header = await this.tokenizer.readToken(ChunkHeader64);
18
21
  if (header.chunkID !== 'FRM8')
19
- throw new Error('Unexpected chunk-ID');
22
+ throw new DsdiffContentParseError('Unexpected chunk-ID');
20
23
  const type = (await this.tokenizer.readToken(FourCcToken)).trim();
21
24
  switch (type) {
22
25
  case 'DSD':
@@ -24,7 +27,7 @@ export class DsdiffParser extends BasicParser {
24
27
  this.metadata.setFormat('lossless', true);
25
28
  return this.readFmt8Chunks(header.chunkSize - BigInt(FourCcToken.len));
26
29
  default:
27
- throw new Error(`Unsupported DSDIFF type: ${type}`);
30
+ throw new DsdiffContentParseError(`Unsupported DSDIFF type: ${type}`);
28
31
  }
29
32
  }
30
33
  async readFmt8Chunks(remainingSize) {
@@ -48,7 +51,7 @@ export class DsdiffParser extends BasicParser {
48
51
  case 'PROP': { // 3.2 PROPERTY CHUNK
49
52
  const propType = await this.tokenizer.readToken(FourCcToken);
50
53
  if (propType !== 'SND ')
51
- throw new Error('Unexpected PROP-chunk ID');
54
+ throw new DsdiffContentParseError('Unexpected PROP-chunk ID');
52
55
  await this.handleSoundPropertyChunks(header.chunkSize - BigInt(FourCcToken.len));
53
56
  break;
54
57
  }
@@ -1,4 +1,18 @@
1
1
  import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
2
+ declare const DsdContentParseError_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 DsdContentParseError extends DsdContentParseError_base {
15
+ }
2
16
  /**
3
17
  * DSF (dsd stream file) File Parser
4
18
  * Ref: https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
@@ -7,3 +21,4 @@ export declare class DsfParser extends AbstractID3Parser {
7
21
  postId3v2Parse(): Promise<void>;
8
22
  private parseChunks;
9
23
  }
24
+ export {};
@@ -2,7 +2,10 @@ import initDebug from 'debug';
2
2
  import { AbstractID3Parser } from '../id3v2/AbstractID3Parser.js';
3
3
  import { ChunkHeader, DsdChunk, FormatChunk } from './DsfChunk.js';
4
4
  import { ID3v2Parser } from "../id3v2/ID3v2Parser.js";
5
+ import { makeUnexpectedFileContentError } from '../ParseError.js';
5
6
  const debug = initDebug('music-metadata:parser:DSF');
7
+ export class DsdContentParseError extends makeUnexpectedFileContentError('DSD') {
8
+ }
6
9
  /**
7
10
  * DSF (dsd stream file) File Parser
8
11
  * Ref: https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
@@ -12,7 +15,7 @@ export class DsfParser extends AbstractID3Parser {
12
15
  const p0 = this.tokenizer.position; // mark start position, normally 0
13
16
  const chunkHeader = await this.tokenizer.readToken(ChunkHeader);
14
17
  if (chunkHeader.id !== 'DSD ')
15
- throw new Error('Invalid chunk signature');
18
+ throw new DsdContentParseError('Invalid chunk signature');
16
19
  this.metadata.setFormat('container', 'DSF');
17
20
  this.metadata.setFormat('lossless', true);
18
21
  const dsdChunk = await this.tokenizer.readToken(DsdChunk);
@@ -1,5 +1,19 @@
1
1
  import { type ITokenizer } from 'strtok3';
2
2
  import { type IElementType, type ITree, type ValueType } from './types.js';
3
+ declare const EbmlContentError_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 EbmlContentError extends EbmlContentError_base {
16
+ }
3
17
  export interface ILinkedElementType extends IElementType {
4
18
  id: number;
5
19
  parent: ILinkedElementType | undefined;
@@ -50,3 +64,4 @@ export declare class EbmlIterator {
50
64
  private readBuffer;
51
65
  }
52
66
  export declare function getElementPath(element: ILinkedElementType): string;
67
+ export {};