music-metadata 11.16.0 → 12.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.
Files changed (61) hide show
  1. package/README.md +6 -5
  2. package/lib/ParseError.d.ts +10 -3
  3. package/lib/ParseError.js +2 -0
  4. package/lib/ParserFactory.js +4 -4
  5. package/lib/aiff/AiffParser.js +1 -4
  6. package/lib/aiff/AiffToken.d.ts +4 -3
  7. package/lib/aiff/AiffToken.js +2 -0
  8. package/lib/apev2/APEv2Parser.d.ts +4 -3
  9. package/lib/apev2/APEv2Parser.js +1 -4
  10. package/lib/asf/AsfGuid.js +49 -49
  11. package/lib/asf/AsfObject.d.ts +4 -3
  12. package/lib/asf/AsfObject.js +14 -9
  13. package/lib/common/BasicParser.js +3 -0
  14. package/lib/common/CombinedTagMapper.js +1 -1
  15. package/lib/common/GenericTagMapper.js +3 -1
  16. package/lib/common/MetadataCollector.d.ts +1 -0
  17. package/lib/common/MetadataCollector.js +31 -24
  18. package/lib/core.js +5 -10
  19. package/lib/dsdiff/DsdiffParser.d.ts +4 -3
  20. package/lib/dsf/DsfParser.d.ts +4 -3
  21. package/lib/ebml/EbmlIterator.d.ts +4 -3
  22. package/lib/ebml/EbmlIterator.js +4 -3
  23. package/lib/flac/FlacParser.js +1 -4
  24. package/lib/id3v1/ID3v1Parser.js +3 -0
  25. package/lib/id3v2/AbstractID3Parser.js +1 -4
  26. package/lib/id3v2/FrameParser.d.ts +4 -3
  27. package/lib/id3v2/FrameParser.js +3 -1
  28. package/lib/id3v2/ID3v2Parser.js +5 -7
  29. package/lib/matroska/MatroskaParser.js +7 -9
  30. package/lib/mp4/Atom.js +6 -0
  31. package/lib/mp4/AtomToken.d.ts +4 -4
  32. package/lib/mp4/AtomToken.js +14 -1
  33. package/lib/mp4/MP4Parser.js +78 -81
  34. package/lib/mpeg/MpegParser.d.ts +4 -3
  35. package/lib/mpeg/MpegParser.js +82 -69
  36. package/lib/musepack/MusepackConentError.d.ts +4 -3
  37. package/lib/musepack/sv7/BitReader.js +3 -2
  38. package/lib/musepack/sv7/MpcSv7Parser.js +3 -6
  39. package/lib/musepack/sv8/MpcSv8Parser.js +1 -4
  40. package/lib/musepack/sv8/StreamVersion8.js +1 -0
  41. package/lib/ogg/OggParser.d.ts +4 -3
  42. package/lib/ogg/OggParser.js +14 -7
  43. package/lib/ogg/OggToken.d.ts +2 -0
  44. package/lib/ogg/OggToken.js +1 -0
  45. package/lib/ogg/flac/FlacStream.js +5 -1
  46. package/lib/ogg/opus/Opus.d.ts +4 -3
  47. package/lib/ogg/opus/Opus.js +1 -0
  48. package/lib/ogg/opus/OpusStream.js +3 -2
  49. package/lib/ogg/speex/SpeexStream.js +1 -1
  50. package/lib/ogg/theora/TheoraStream.js +2 -1
  51. package/lib/ogg/vorbis/Vorbis.js +1 -0
  52. package/lib/ogg/vorbis/VorbisDecoder.js +2 -0
  53. package/lib/ogg/vorbis/VorbisStream.d.ts +5 -3
  54. package/lib/ogg/vorbis/VorbisStream.js +7 -2
  55. package/lib/riff/RiffChunk.js +3 -0
  56. package/lib/wav/WaveChunk.d.ts +4 -3
  57. package/lib/wav/WaveChunk.js +2 -0
  58. package/lib/wav/WaveParser.js +7 -6
  59. package/lib/wavpack/WavPackParser.d.ts +4 -3
  60. package/lib/wavpack/WavPackParser.js +1 -4
  61. package/package.json +20 -16
package/README.md CHANGED
@@ -23,12 +23,12 @@ The [`music-metadata`](https://github.com/Borewit/music-metadata) module is idea
23
23
  ## Compatibility
24
24
 
25
25
  Module: version 8 migrated from [CommonJS](https://en.wikipedia.org/wiki/CommonJS) to [pure ECMAScript Module (ESM)](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
26
- The distributed JavaScript codebase is compliant with the [ECMAScript 2020 (11th Edition)](https://en.wikipedia.org/wiki/ECMAScript_version_history#11th_Edition_%E2%80%93_ECMAScript_2020) standard.
26
+ The distributed JavaScript codebase targets [ECMAScript 2023 (14th Edition)](https://262.ecma-international.org/14.0/).
27
27
 
28
28
  > [!NOTE]
29
29
  > See also [CommonJS backward Compatibility](#commonjs-backward-compatibility)
30
30
 
31
- This module requires a [Node.js ≥ 18](https://nodejs.org/en/about/previous-releases) engine.
31
+ This module requires a [Node.js ≥ 22](https://nodejs.org/en/about/previous-releases) engine.
32
32
  It can also be used in a browser environment when bundled with a module bundler.
33
33
 
34
34
  ## Support the Project
@@ -99,11 +99,12 @@ Support for encoding / format details:
99
99
 
100
100
 
101
101
  ## Online demo's
102
- - [<img src="https://raw.githubusercontent.com/Borewit/audio-tag-analyzer/master/src/assets/icon/audio-tag-analyzer.svg" width="40">Audio Tag Analyzer](https://audio-tag-analyzer.netlify.app/)
103
- - [<img src="https://cdn.sanity.io/images/3do82whm/next/ba8c847f13a5fa39d88f8bc9b7846b7886531b18-2500x2500.svg" width="40"> Webamp](https://webamp.org/)
102
+ - [<img src="https://raw.githubusercontent.com/Borewit/audio-tag-analyzer-vite/master/public/favicon.svg" width="40" alt="Audio Tag Analyzer logo"> Audio Tag Analyzer](https://audio-tag-analyzer.netlify.app/) ([source code](https://github.com/Borewit/audio-tag-analyzer-vite))
104
103
  - [ICY Radio Stream Player](https://icy-radio-stream-player.netlify.app/)
105
104
  - Expected to be released soon: [Overtone](https://overtone.pro/) by [Johannes Schickling](https://github.com/schickling)
106
105
 
106
+ Used by [around 50k+ GitHub projects](https://github.com/Borewit/music-metadata/network/dependents).
107
+
107
108
  ## Usage
108
109
 
109
110
  ### Installation
@@ -799,7 +800,7 @@ Using Node.js ≥ 22, which is support loading ESM module via require
799
800
  const mm = require('music-metadata');
800
801
  ```
801
802
 
802
- For older Node.js version < 22, you need to dynamically import **music-metadata**:
803
+ Alternatively, dynamically import **music-metadata**:
803
804
  ```js
804
805
  (async () => {
805
806
  // Dynamically loads the ESM module in a CommonJS project
@@ -4,6 +4,7 @@ export declare const makeParseError: <Name extends string>(name: Name) => {
4
4
  name: Name;
5
5
  message: string;
6
6
  stack?: string;
7
+ cause?: unknown;
7
8
  };
8
9
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
9
10
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -14,6 +15,7 @@ declare const CouldNotDetermineFileTypeError_base: {
14
15
  name: "CouldNotDetermineFileTypeError";
15
16
  message: string;
16
17
  stack?: string;
18
+ cause?: unknown;
17
19
  };
18
20
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
19
21
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -26,6 +28,7 @@ declare const UnsupportedFileTypeError_base: {
26
28
  name: "UnsupportedFileTypeError";
27
29
  message: string;
28
30
  stack?: string;
31
+ cause?: unknown;
29
32
  };
30
33
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
31
34
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -38,6 +41,7 @@ declare const UnexpectedFileContentError_base: {
38
41
  name: "UnexpectedFileContentError";
39
42
  message: string;
40
43
  stack?: string;
44
+ cause?: unknown;
41
45
  };
42
46
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
43
47
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -53,6 +57,7 @@ declare const FieldDecodingError_base: {
53
57
  name: "FieldDecodingError";
54
58
  message: string;
55
59
  stack?: string;
60
+ cause?: unknown;
56
61
  };
57
62
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
58
63
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -65,6 +70,7 @@ declare const InternalParserError_base: {
65
70
  name: "InternalParserError";
66
71
  message: string;
67
72
  stack?: string;
73
+ cause?: unknown;
68
74
  };
69
75
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
70
76
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -74,11 +80,12 @@ export declare class InternalParserError extends InternalParserError_base {
74
80
  }
75
81
  export declare const makeUnexpectedFileContentError: <FileType extends string>(fileType: FileType) => {
76
82
  new (message: string): {
77
- readonly fileType: string;
78
- toString(): string;
79
- name: "UnexpectedFileContentError";
80
83
  message: string;
81
84
  stack?: string;
85
+ cause?: unknown;
86
+ name: "UnexpectedFileContentError";
87
+ readonly fileType: string;
88
+ toString(): string;
82
89
  };
83
90
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
84
91
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
package/lib/ParseError.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export const makeParseError = (name) => {
2
2
  return class ParseError extends Error {
3
+ name;
3
4
  constructor(message) {
4
5
  super(message);
5
6
  this.name = name;
@@ -14,6 +15,7 @@ export class UnsupportedFileTypeError extends makeParseError('UnsupportedFileTyp
14
15
  }
15
16
  // Concrete error class representing unexpected file content.
16
17
  export class UnexpectedFileContentError extends makeParseError('UnexpectedFileContentError') {
18
+ fileType;
17
19
  constructor(fileType, message) {
18
20
  super(message);
19
21
  this.fileType = fileType;
@@ -1,4 +1,4 @@
1
- import ContentType from 'content-type';
1
+ import { parse as parseContentType } from 'content-type';
2
2
  import initDebug from 'debug';
3
3
  import { fileTypeFromBuffer } from 'file-type';
4
4
  import { parse as mimeTypeParse } from 'media-typer';
@@ -21,7 +21,7 @@ import { riffParserLoader } from './wav/WaveLoader.js';
21
21
  import { wavpackParserLoader } from './wavpack/WavPackLoader.js';
22
22
  const debug = initDebug('music-metadata:parser:factory');
23
23
  export function parseHttpContentType(contentType) {
24
- const type = ContentType.parse(contentType);
24
+ const type = parseContentType(contentType);
25
25
  const mime = mimeTypeParse(type.type);
26
26
  return {
27
27
  type: mime.type,
@@ -31,8 +31,8 @@ export function parseHttpContentType(contentType) {
31
31
  };
32
32
  }
33
33
  export class ParserFactory {
34
+ parsers = [];
34
35
  constructor() {
35
- this.parsers = [];
36
36
  [
37
37
  flacParserLoader,
38
38
  mpegParserLoader,
@@ -54,7 +54,7 @@ export class ParserFactory {
54
54
  registerParser(parser) {
55
55
  this.parsers.push(parser);
56
56
  }
57
- async parse(tokenizer, parserLoader, opts) {
57
+ async parse(tokenizer, parserLoader, opts = {}) {
58
58
  if (tokenizer.supportsRandomAccess()) {
59
59
  debug('tokenizer supports random-access, scanning for appending headers');
60
60
  await scanAppendingHeaders(tokenizer, opts);
@@ -16,10 +16,7 @@ const debug = initDebug('music-metadata:parser:aiff');
16
16
  * - http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/Docs/AIFF-1.3.pdf
17
17
  */
18
18
  export class AIFFParser extends BasicParser {
19
- constructor() {
20
- super(...arguments);
21
- this.isCompressed = null;
22
- }
19
+ isCompressed = null;
23
20
  async parse() {
24
21
  const header = await this.tokenizer.readToken(iff.Header);
25
22
  if (header.chunkID !== 'FORM') {
@@ -14,11 +14,12 @@ export declare const compressionTypes: {
14
14
  export type CompressionTypeCode = keyof typeof compressionTypes;
15
15
  declare const AiffContentError_base: {
16
16
  new (message: string): {
17
- readonly fileType: string;
18
- toString(): string;
19
- name: "UnexpectedFileContentError";
20
17
  message: string;
21
18
  stack?: string;
19
+ cause?: unknown;
20
+ name: "UnexpectedFileContentError";
21
+ readonly fileType: string;
22
+ toString(): string;
22
23
  };
23
24
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
24
25
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -15,6 +15,8 @@ export const compressionTypes = {
15
15
  export class AiffContentError extends makeUnexpectedFileContentError('AIFF') {
16
16
  }
17
17
  export class Common {
18
+ len;
19
+ isAifc;
18
20
  constructor(header, isAifc) {
19
21
  this.isAifc = isAifc;
20
22
  const minimumChunkSize = isAifc ? 22 : 18;
@@ -6,11 +6,12 @@ import type { IApeHeader, IOptions } from '../type.js';
6
6
  import { type IFooter, type IHeader } from './APEv2Token.js';
7
7
  declare const ApeContentError_base: {
8
8
  new (message: string): {
9
- readonly fileType: string;
10
- toString(): string;
11
- name: "UnexpectedFileContentError";
12
9
  message: string;
13
10
  stack?: string;
11
+ cause?: unknown;
12
+ name: "UnexpectedFileContentError";
13
+ readonly fileType: string;
14
+ toString(): string;
14
15
  };
15
16
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
16
17
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -16,10 +16,6 @@ export function tryParseApeHeader(metadata, tokenizer, options) {
16
16
  return apeParser.tryParseApeHeader();
17
17
  }
18
18
  export class APEv2Parser extends BasicParser {
19
- constructor() {
20
- super(...arguments);
21
- this.ape = {};
22
- }
23
19
  /**
24
20
  * Calculate the media file duration
25
21
  * @param ah ApeHeader
@@ -68,6 +64,7 @@ export class APEv2Parser extends BasicParser {
68
64
  const apeParser = new APEv2Parser(metadata, strtok3.fromBuffer(buffer), options);
69
65
  return apeParser.parseTags(footer);
70
66
  }
67
+ ape = {};
71
68
  /**
72
69
  * Parse APEv1 / APEv2 header if header signature found
73
70
  */
@@ -13,7 +13,54 @@ import { Guid, parseWindowsGuid } from 'win-guid';
13
13
  * - http://drang.s4.xrea.com/program/tips/id3tag/wmp/10_asf_guids.html
14
14
  * - https://github.com/dji-sdk/FFmpeg/blob/master/libavformat/asf.c
15
15
  */
16
- class AsfGuid {
16
+ export default class AsfGuid {
17
+ // 10.1 Top-level ASF object GUIDs
18
+ static HeaderObject = new AsfGuid('75B22630-668E-11CF-A6D9-00AA0062CE6C');
19
+ static DataObject = new AsfGuid('75B22636-668E-11CF-A6D9-00AA0062CE6C');
20
+ static SimpleIndexObject = new AsfGuid('33000890-E5B1-11CF-89F4-00A0C90349CB');
21
+ static IndexObject = new AsfGuid('D6E229D3-35DA-11D1-9034-00A0C90349BE');
22
+ static MediaObjectIndexObject = new AsfGuid('FEB103F8-12AD-4C64-840F-2A1D2F7AD48C');
23
+ static TimecodeIndexObject = new AsfGuid('3CB73FD0-0C4A-4803-953D-EDF7B6228F0C');
24
+ // 10.2 Header Object GUIDs
25
+ static FilePropertiesObject = new AsfGuid('8CABDCA1-A947-11CF-8EE4-00C00C205365');
26
+ static StreamPropertiesObject = new AsfGuid('B7DC0791-A9B7-11CF-8EE6-00C00C205365');
27
+ static HeaderExtensionObject = new AsfGuid('5FBF03B5-A92E-11CF-8EE3-00C00C205365');
28
+ static CodecListObject = new AsfGuid('86D15240-311D-11D0-A3A4-00A0C90348F6');
29
+ static ScriptCommandObject = new AsfGuid('1EFB1A30-0B62-11D0-A39B-00A0C90348F6');
30
+ static MarkerObject = new AsfGuid('F487CD01-A951-11CF-8EE6-00C00C205365');
31
+ static BitrateMutualExclusionObject = new AsfGuid('D6E229DC-35DA-11D1-9034-00A0C90349BE');
32
+ static ErrorCorrectionObject = new AsfGuid('75B22635-668E-11CF-A6D9-00AA0062CE6C');
33
+ static ContentDescriptionObject = new AsfGuid('75B22633-668E-11CF-A6D9-00AA0062CE6C');
34
+ static ExtendedContentDescriptionObject = new AsfGuid('D2D0A440-E307-11D2-97F0-00A0C95EA850');
35
+ static ContentBrandingObject = new AsfGuid('2211B3FA-BD23-11D2-B4B7-00A0C955FC6E');
36
+ static StreamBitratePropertiesObject = new AsfGuid('7BF875CE-468D-11D1-8D82-006097C9A2B2');
37
+ static ContentEncryptionObject = new AsfGuid('2211B3FB-BD23-11D2-B4B7-00A0C955FC6E');
38
+ static ExtendedContentEncryptionObject = new AsfGuid('298AE614-2622-4C17-B935-DAE07EE9289C');
39
+ static DigitalSignatureObject = new AsfGuid('2211B3FC-BD23-11D2-B4B7-00A0C955FC6E');
40
+ static PaddingObject = new AsfGuid('1806D474-CADF-4509-A4BA-9AABCB96AAE8');
41
+ // 10.3 Header Extension Object GUIDs
42
+ static ExtendedStreamPropertiesObject = new AsfGuid('14E6A5CB-C672-4332-8399-A96952065B5A');
43
+ static AdvancedMutualExclusionObject = new AsfGuid('A08649CF-4775-4670-8A16-6E35357566CD');
44
+ static GroupMutualExclusionObject = new AsfGuid('D1465A40-5A79-4338-B71B-E36B8FD6C249');
45
+ static StreamPrioritizationObject = new AsfGuid('D4FED15B-88D3-454F-81F0-ED5C45999E24');
46
+ static BandwidthSharingObject = new AsfGuid('A69609E6-517B-11D2-B6AF-00C04FD908E9');
47
+ static LanguageListObject = new AsfGuid('7C4346A9-EFE0-4BFC-B229-393EDE415C85');
48
+ static MetadataObject = new AsfGuid('C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA');
49
+ static MetadataLibraryObject = new AsfGuid('44231C94-9498-49D1-A141-1D134E457054');
50
+ static IndexParametersObject = new AsfGuid('D6E229DF-35DA-11D1-9034-00A0C90349BE');
51
+ static MediaObjectIndexParametersObject = new AsfGuid('6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7');
52
+ static TimecodeIndexParametersObject = new AsfGuid('F55E496D-9797-4B5D-8C8B-604DFE9BFB24');
53
+ static CompatibilityObject = new AsfGuid('26F18B5D-4584-47EC-9F5F-0E651F0452C9');
54
+ static AdvancedContentEncryptionObject = new AsfGuid('43058533-6981-49E6-9B74-AD12CB86D58C');
55
+ // 10.4 Stream Properties Object Stream Type GUIDs
56
+ static AudioMedia = new AsfGuid('F8699E40-5B4D-11CF-A8FD-00805F5C442B');
57
+ static VideoMedia = new AsfGuid('BC19EFC0-5B4D-11CF-A8FD-00805F5C442B');
58
+ static CommandMedia = new AsfGuid('59DACFC0-59E6-11D0-A3AC-00A0C90348F6');
59
+ static JFIF_Media = new AsfGuid('B61BE100-5B4E-11CF-A8FD-00805F5C442B');
60
+ static Degradable_JPEG_Media = new AsfGuid('35907DE0-E415-11CF-A917-00805F5C442B');
61
+ static FileTransferMedia = new AsfGuid('91BD222C-F21C-497A-8B6D-5AA86BFC0185');
62
+ static BinaryMedia = new AsfGuid('3AFB65E2-47EF-40F2-AC2C-70A90D71D343');
63
+ static ASF_Index_Placeholder_Object = new AsfGuid('D9AADE20-7C17-4F9C-BC28-8555DD98E2A2');
17
64
  static fromBin(bin, offset = 0) {
18
65
  return new AsfGuid(AsfGuid.decode(bin, offset));
19
66
  }
@@ -55,6 +102,7 @@ class AsfGuid {
55
102
  static encode(guid) {
56
103
  return parseWindowsGuid(guid);
57
104
  }
105
+ str;
58
106
  constructor(str) {
59
107
  this.str = str;
60
108
  }
@@ -65,51 +113,3 @@ class AsfGuid {
65
113
  return AsfGuid.encode(this.str);
66
114
  }
67
115
  }
68
- // 10.1 Top-level ASF object GUIDs
69
- AsfGuid.HeaderObject = new AsfGuid('75B22630-668E-11CF-A6D9-00AA0062CE6C');
70
- AsfGuid.DataObject = new AsfGuid('75B22636-668E-11CF-A6D9-00AA0062CE6C');
71
- AsfGuid.SimpleIndexObject = new AsfGuid('33000890-E5B1-11CF-89F4-00A0C90349CB');
72
- AsfGuid.IndexObject = new AsfGuid('D6E229D3-35DA-11D1-9034-00A0C90349BE');
73
- AsfGuid.MediaObjectIndexObject = new AsfGuid('FEB103F8-12AD-4C64-840F-2A1D2F7AD48C');
74
- AsfGuid.TimecodeIndexObject = new AsfGuid('3CB73FD0-0C4A-4803-953D-EDF7B6228F0C');
75
- // 10.2 Header Object GUIDs
76
- AsfGuid.FilePropertiesObject = new AsfGuid('8CABDCA1-A947-11CF-8EE4-00C00C205365');
77
- AsfGuid.StreamPropertiesObject = new AsfGuid('B7DC0791-A9B7-11CF-8EE6-00C00C205365');
78
- AsfGuid.HeaderExtensionObject = new AsfGuid('5FBF03B5-A92E-11CF-8EE3-00C00C205365');
79
- AsfGuid.CodecListObject = new AsfGuid('86D15240-311D-11D0-A3A4-00A0C90348F6');
80
- AsfGuid.ScriptCommandObject = new AsfGuid('1EFB1A30-0B62-11D0-A39B-00A0C90348F6');
81
- AsfGuid.MarkerObject = new AsfGuid('F487CD01-A951-11CF-8EE6-00C00C205365');
82
- AsfGuid.BitrateMutualExclusionObject = new AsfGuid('D6E229DC-35DA-11D1-9034-00A0C90349BE');
83
- AsfGuid.ErrorCorrectionObject = new AsfGuid('75B22635-668E-11CF-A6D9-00AA0062CE6C');
84
- AsfGuid.ContentDescriptionObject = new AsfGuid('75B22633-668E-11CF-A6D9-00AA0062CE6C');
85
- AsfGuid.ExtendedContentDescriptionObject = new AsfGuid('D2D0A440-E307-11D2-97F0-00A0C95EA850');
86
- AsfGuid.ContentBrandingObject = new AsfGuid('2211B3FA-BD23-11D2-B4B7-00A0C955FC6E');
87
- AsfGuid.StreamBitratePropertiesObject = new AsfGuid('7BF875CE-468D-11D1-8D82-006097C9A2B2');
88
- AsfGuid.ContentEncryptionObject = new AsfGuid('2211B3FB-BD23-11D2-B4B7-00A0C955FC6E');
89
- AsfGuid.ExtendedContentEncryptionObject = new AsfGuid('298AE614-2622-4C17-B935-DAE07EE9289C');
90
- AsfGuid.DigitalSignatureObject = new AsfGuid('2211B3FC-BD23-11D2-B4B7-00A0C955FC6E');
91
- AsfGuid.PaddingObject = new AsfGuid('1806D474-CADF-4509-A4BA-9AABCB96AAE8');
92
- // 10.3 Header Extension Object GUIDs
93
- AsfGuid.ExtendedStreamPropertiesObject = new AsfGuid('14E6A5CB-C672-4332-8399-A96952065B5A');
94
- AsfGuid.AdvancedMutualExclusionObject = new AsfGuid('A08649CF-4775-4670-8A16-6E35357566CD');
95
- AsfGuid.GroupMutualExclusionObject = new AsfGuid('D1465A40-5A79-4338-B71B-E36B8FD6C249');
96
- AsfGuid.StreamPrioritizationObject = new AsfGuid('D4FED15B-88D3-454F-81F0-ED5C45999E24');
97
- AsfGuid.BandwidthSharingObject = new AsfGuid('A69609E6-517B-11D2-B6AF-00C04FD908E9');
98
- AsfGuid.LanguageListObject = new AsfGuid('7C4346A9-EFE0-4BFC-B229-393EDE415C85');
99
- AsfGuid.MetadataObject = new AsfGuid('C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA');
100
- AsfGuid.MetadataLibraryObject = new AsfGuid('44231C94-9498-49D1-A141-1D134E457054');
101
- AsfGuid.IndexParametersObject = new AsfGuid('D6E229DF-35DA-11D1-9034-00A0C90349BE');
102
- AsfGuid.MediaObjectIndexParametersObject = new AsfGuid('6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7');
103
- AsfGuid.TimecodeIndexParametersObject = new AsfGuid('F55E496D-9797-4B5D-8C8B-604DFE9BFB24');
104
- AsfGuid.CompatibilityObject = new AsfGuid('26F18B5D-4584-47EC-9F5F-0E651F0452C9');
105
- AsfGuid.AdvancedContentEncryptionObject = new AsfGuid('43058533-6981-49E6-9B74-AD12CB86D58C');
106
- // 10.4 Stream Properties Object Stream Type GUIDs
107
- AsfGuid.AudioMedia = new AsfGuid('F8699E40-5B4D-11CF-A8FD-00805F5C442B');
108
- AsfGuid.VideoMedia = new AsfGuid('BC19EFC0-5B4D-11CF-A8FD-00805F5C442B');
109
- AsfGuid.CommandMedia = new AsfGuid('59DACFC0-59E6-11D0-A3AC-00A0C90348F6');
110
- AsfGuid.JFIF_Media = new AsfGuid('B61BE100-5B4E-11CF-A8FD-00805F5C442B');
111
- AsfGuid.Degradable_JPEG_Media = new AsfGuid('35907DE0-E415-11CF-A917-00805F5C442B');
112
- AsfGuid.FileTransferMedia = new AsfGuid('91BD222C-F21C-497A-8B6D-5AA86BFC0185');
113
- AsfGuid.BinaryMedia = new AsfGuid('3AFB65E2-47EF-40F2-AC2C-70A90D71D343');
114
- AsfGuid.ASF_Index_Placeholder_Object = new AsfGuid('D9AADE20-7C17-4F9C-BC28-8555DD98E2A2');
115
- export default AsfGuid;
@@ -3,11 +3,12 @@ import type { AnyTagValue, IPicture, ITag } from '../type.js';
3
3
  import AsfGuid from './AsfGuid.js';
4
4
  declare const AsfContentParseError_base: {
5
5
  new (message: string): {
6
- readonly fileType: string;
7
- toString(): string;
8
- name: "UnexpectedFileContentError";
9
6
  message: string;
10
7
  stack?: string;
8
+ cause?: unknown;
9
+ name: "UnexpectedFileContentError";
10
+ readonly fileType: string;
11
+ toString(): string;
11
12
  };
12
13
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
13
14
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
@@ -73,6 +73,7 @@ export const HeaderObjectToken = {
73
73
  }
74
74
  };
75
75
  export class State {
76
+ len;
76
77
  constructor(header) {
77
78
  this.len = header.objectSize - HeaderObjectToken.len;
78
79
  }
@@ -94,6 +95,7 @@ export class State {
94
95
  * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_2
95
96
  */
96
97
  export class FilePropertiesObject extends State {
98
+ static guid = AsfGuid.FilePropertiesObject;
97
99
  get(buf, off) {
98
100
  return {
99
101
  fileId: AsfGuid.fromBin(buf, off),
@@ -114,12 +116,12 @@ export class FilePropertiesObject extends State {
114
116
  };
115
117
  }
116
118
  }
117
- FilePropertiesObject.guid = AsfGuid.FilePropertiesObject;
118
119
  /**
119
120
  * Token for: 3.3 Stream Properties Object (mandatory, one per stream)
120
121
  * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_3
121
122
  */
122
123
  export class StreamPropertiesObject extends State {
124
+ static guid = AsfGuid.StreamPropertiesObject;
123
125
  get(buf, off) {
124
126
  return {
125
127
  streamType: AsfGuid.decodeMediaType(AsfGuid.fromBin(buf, off)),
@@ -128,12 +130,13 @@ export class StreamPropertiesObject extends State {
128
130
  };
129
131
  }
130
132
  }
131
- StreamPropertiesObject.guid = AsfGuid.StreamPropertiesObject;
132
133
  /**
133
134
  * 3.4: Header Extension Object (mandatory, one only)
134
135
  * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_4
135
136
  */
136
137
  export class HeaderExtensionObject {
138
+ static guid = AsfGuid.HeaderExtensionObject;
139
+ len;
137
140
  constructor() {
138
141
  this.len = 22;
139
142
  }
@@ -146,7 +149,6 @@ export class HeaderExtensionObject {
146
149
  };
147
150
  }
148
151
  }
149
- HeaderExtensionObject.guid = AsfGuid.HeaderExtensionObject;
150
152
  /**
151
153
  * 3.5: The Codec List Object provides user-friendly information about the codecs and formats used to encode the content found in the ASF file.
152
154
  * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_5
@@ -161,6 +163,8 @@ const CodecListObjectHeader = {
161
163
  }
162
164
  };
163
165
  class BoundedReader {
166
+ tokenizer;
167
+ remaining;
164
168
  constructor(tokenizer, size) {
165
169
  this.tokenizer = tokenizer;
166
170
  this.remaining = size;
@@ -237,6 +241,8 @@ async function readCodecEntry(reader) {
237
241
  * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_10
238
242
  */
239
243
  export class ContentDescriptionObjectState extends State {
244
+ static guid = AsfGuid.ContentDescriptionObject;
245
+ static contentDescTags = ['Title', 'Author', 'Copyright', 'Description', 'Rating'];
240
246
  get(buf, off) {
241
247
  const tags = [];
242
248
  const view = new DataView(buf.buffer, off);
@@ -253,13 +259,12 @@ export class ContentDescriptionObjectState extends State {
253
259
  return tags;
254
260
  }
255
261
  }
256
- ContentDescriptionObjectState.guid = AsfGuid.ContentDescriptionObject;
257
- ContentDescriptionObjectState.contentDescTags = ['Title', 'Author', 'Copyright', 'Description', 'Rating'];
258
262
  /**
259
263
  * 3.11 Extended Content Description Object (optional, one only)
260
264
  * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_11
261
265
  */
262
266
  export class ExtendedContentDescriptionObjectState extends State {
267
+ static guid = AsfGuid.ExtendedContentDescriptionObject;
263
268
  get(buf, off) {
264
269
  const tags = [];
265
270
  const view = new DataView(buf.buffer, off);
@@ -281,12 +286,12 @@ export class ExtendedContentDescriptionObjectState extends State {
281
286
  return tags;
282
287
  }
283
288
  }
284
- ExtendedContentDescriptionObjectState.guid = AsfGuid.ExtendedContentDescriptionObject;
285
289
  /**
286
290
  * 4.1 Extended Stream Properties Object (optional, 1 per media stream)
287
291
  * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/04_objects_in_the_asf_header_extension_object.html#4_1
288
292
  */
289
293
  export class ExtendedStreamPropertiesObjectState extends State {
294
+ static guid = AsfGuid.ExtendedStreamPropertiesObject;
290
295
  get(buf, off) {
291
296
  const view = new DataView(buf.buffer, off);
292
297
  return {
@@ -316,12 +321,12 @@ export class ExtendedStreamPropertiesObjectState extends State {
316
321
  };
317
322
  }
318
323
  }
319
- ExtendedStreamPropertiesObjectState.guid = AsfGuid.ExtendedStreamPropertiesObject;
320
324
  /**
321
325
  * 4.7 Metadata Object (optional, 0 or 1)
322
326
  * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/04_objects_in_the_asf_header_extension_object.html#4_7
323
327
  */
324
328
  export class MetadataObjectState extends State {
329
+ static guid = AsfGuid.MetadataObject;
325
330
  get(uint8Array, off) {
326
331
  const tags = [];
327
332
  const view = new DataView(uint8Array.buffer, off);
@@ -344,11 +349,10 @@ export class MetadataObjectState extends State {
344
349
  return tags;
345
350
  }
346
351
  }
347
- MetadataObjectState.guid = AsfGuid.MetadataObject;
348
352
  // 4.8 Metadata Library Object (optional, 0 or 1)
349
353
  export class MetadataLibraryObjectState extends MetadataObjectState {
354
+ static guid = AsfGuid.MetadataLibraryObject;
350
355
  }
351
- MetadataLibraryObjectState.guid = AsfGuid.MetadataLibraryObject;
352
356
  /**
353
357
  * Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd757977(v=vs.85).aspx
354
358
  */
@@ -357,6 +361,7 @@ export class WmPictureToken {
357
361
  const pic = new WmPictureToken(buffer.length);
358
362
  return pic.get(buffer, 0);
359
363
  }
364
+ len;
360
365
  constructor(len) {
361
366
  this.len = len;
362
367
  }
@@ -1,4 +1,7 @@
1
1
  export class BasicParser {
2
+ metadata;
3
+ tokenizer;
4
+ options;
2
5
  /**
3
6
  * Initialize parser with output (metadata), input (tokenizer) & parsing options (options).
4
7
  * @param {INativeMetadataCollector} metadata Output
@@ -10,8 +10,8 @@ import { VorbisTagMapper } from '../ogg/vorbis/VorbisTagMapper.js';
10
10
  import { InternalParserError } from '../ParseError.js';
11
11
  import { RiffInfoTagMapper } from '../riff/RiffInfoTagMap.js';
12
12
  export class CombinedTagMapper {
13
+ tagMappers = {};
13
14
  constructor() {
14
- this.tagMappers = {};
15
15
  [
16
16
  new ID3v1TagMapper(),
17
17
  new ID3v22TagMapper(),
@@ -1,4 +1,5 @@
1
1
  export class CommonTagMapper {
2
+ static maxRatingScore = 1;
2
3
  static toIntOrNull(str) {
3
4
  const cleaned = Number.parseInt(str, 10);
4
5
  return Number.isNaN(cleaned) ? null : cleaned;
@@ -13,6 +14,8 @@ export class CommonTagMapper {
13
14
  of: Number.parseInt(split[1], 10) || null
14
15
  };
15
16
  }
17
+ tagTypes;
18
+ tagMap;
16
19
  constructor(tagTypes, tagMap) {
17
20
  this.tagTypes = tagTypes;
18
21
  this.tagMap = tagMap;
@@ -48,4 +51,3 @@ export class CommonTagMapper {
48
51
  return;
49
52
  }
50
53
  }
51
- CommonTagMapper.maxRatingScore = 1;
@@ -84,5 +84,6 @@ export declare class MetadataCollector implements INativeMetadataCollector {
84
84
  * Set generic tag
85
85
  */
86
86
  private setGenericTag;
87
+ private notifyCommonTag;
87
88
  }
88
89
  export declare function joinArtists(artists: string[]): string;
@@ -25,29 +25,30 @@ const TagPriority = [
25
25
  * Responsible for triggering async updates
26
26
  */
27
27
  export class MetadataCollector {
28
+ format = {
29
+ tagTypes: [],
30
+ trackInfo: []
31
+ };
32
+ native = {};
33
+ common = {
34
+ track: { no: null, of: null },
35
+ disk: { no: null, of: null },
36
+ movementIndex: { no: null, of: null }
37
+ };
38
+ quality = {
39
+ warnings: []
40
+ };
41
+ /**
42
+ * Keeps track of origin priority for each mapped id
43
+ */
44
+ commonOrigin = {};
45
+ /**
46
+ * Maps a tag type to a priority
47
+ */
48
+ originPriority = {};
49
+ tagMapper = new CombinedTagMapper();
50
+ opts;
28
51
  constructor(opts) {
29
- this.format = {
30
- tagTypes: [],
31
- trackInfo: []
32
- };
33
- this.native = {};
34
- this.common = {
35
- track: { no: null, of: null },
36
- disk: { no: null, of: null },
37
- movementIndex: { no: null, of: null }
38
- };
39
- this.quality = {
40
- warnings: []
41
- };
42
- /**
43
- * Keeps track of origin priority for each mapped id
44
- */
45
- this.commonOrigin = {};
46
- /**
47
- * Maps a tag type to a priority
48
- */
49
- this.originPriority = {};
50
- this.tagMapper = new CombinedTagMapper();
51
52
  this.opts = opts;
52
53
  let priority = 1;
53
54
  for (const tagType of TagPriority) {
@@ -117,12 +118,15 @@ export class MetadataCollector {
117
118
  });
118
119
  case 'totaltracks':
119
120
  this.common.track.of = CommonTagMapper.toIntOrNull(tag.value);
121
+ this.notifyCommonTag({ id: 'track', value: { ...this.common.track } });
120
122
  return;
121
123
  case 'totaldiscs':
122
124
  this.common.disk.of = CommonTagMapper.toIntOrNull(tag.value);
125
+ this.notifyCommonTag({ id: 'disk', value: { ...this.common.disk } });
123
126
  return;
124
127
  case 'movementTotal':
125
128
  this.common.movementIndex.of = CommonTagMapper.toIntOrNull(tag.value);
129
+ this.notifyCommonTag({ id: 'movementIndex', value: { ...this.common.movementIndex } });
126
130
  return;
127
131
  case 'track':
128
132
  case 'disk':
@@ -130,6 +134,7 @@ export class MetadataCollector {
130
134
  const of = this.common[tag.id].of; // store of value, maybe maybe overwritten
131
135
  this.common[tag.id] = CommonTagMapper.normalizeTrack(tag.value);
132
136
  this.common[tag.id].of = of != null ? of : this.common[tag.id].of;
137
+ this.notifyCommonTag({ id: tag.id, value: { ...this.common[tag.id] } });
133
138
  return;
134
139
  }
135
140
  case 'bpm':
@@ -300,7 +305,7 @@ export class MetadataCollector {
300
305
  this.common[tag.id].push(tag.value);
301
306
  }
302
307
  else {
303
- debug(`Ignore duplicate value: ${tagType}.${tag.id} = ${tag.value}`);
308
+ return debug(`Ignore duplicate value: ${tagType}.${tag.id} = ${tag.value}`);
304
309
  }
305
310
  // no effect? this.commonOrigin[tag.id] = prio1;
306
311
  }
@@ -312,10 +317,12 @@ export class MetadataCollector {
312
317
  return debug(`Ignore native tag (list): ${tagType}.${tag.id} = ${tag.value}`);
313
318
  }
314
319
  }
320
+ this.notifyCommonTag(tag);
321
+ }
322
+ notifyCommonTag(tag) {
315
323
  if (this.opts?.observer) {
316
324
  this.opts.observer({ metadata: this, tag: { type: 'common', id: tag.id, value: tag.value } });
317
325
  }
318
- // ToDo: trigger metadata event
319
326
  }
320
327
  }
321
328
  export function joinArtists(artists) {