music-metadata 10.0.1 → 10.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/LICENSE.txt +9 -9
  2. package/README.md +535 -520
  3. package/lib/ParserFactory.d.ts +20 -28
  4. package/lib/ParserFactory.js +204 -207
  5. package/lib/aiff/AiffParser.js +20 -19
  6. package/lib/aiff/AiffToken.d.ts +14 -2
  7. package/lib/aiff/AiffToken.js +12 -0
  8. package/lib/apev2/APEv2Parser.d.ts +4 -4
  9. package/lib/apev2/APEv2Parser.js +12 -10
  10. package/lib/apev2/APEv2Token.d.ts +2 -4
  11. package/lib/apev2/APEv2Token.js +0 -3
  12. package/lib/asf/AsfObject.d.ts +7 -16
  13. package/lib/asf/AsfObject.js +8 -34
  14. package/lib/asf/AsfParser.js +17 -10
  15. package/lib/asf/AsfTagMapper.d.ts +1 -1
  16. package/lib/asf/AsfTagMapper.js +3 -2
  17. package/lib/asf/AsfUtil.d.ts +3 -11
  18. package/lib/asf/AsfUtil.js +29 -30
  19. package/lib/asf/GUID.js +6 -9
  20. package/lib/common/BasicParser.d.ts +4 -4
  21. package/lib/common/BasicParser.js +6 -0
  22. package/lib/common/CaseInsensitiveTagMap.d.ts +1 -1
  23. package/lib/common/CombinedTagMapper.d.ts +5 -5
  24. package/lib/common/CombinedTagMapper.js +1 -1
  25. package/lib/common/FourCC.d.ts +1 -1
  26. package/lib/common/GenericTagMapper.d.ts +8 -8
  27. package/lib/common/GenericTagMapper.js +4 -4
  28. package/lib/common/GenericTagTypes.d.ts +5 -4
  29. package/lib/common/GenericTagTypes.js +2 -2
  30. package/lib/common/MetadataCollector.d.ts +9 -9
  31. package/lib/common/MetadataCollector.js +22 -17
  32. package/lib/common/RandomFileReader.d.ts +1 -1
  33. package/lib/common/RandomFileReader.js +1 -1
  34. package/lib/common/RandomUint8ArrayReader.d.ts +1 -1
  35. package/lib/common/Util.d.ts +2 -6
  36. package/lib/common/Util.js +9 -11
  37. package/lib/core.d.ts +7 -9
  38. package/lib/core.js +10 -7
  39. package/lib/dsdiff/DsdiffParser.js +26 -14
  40. package/lib/dsdiff/DsdiffToken.d.ts +2 -2
  41. package/lib/dsdiff/DsdiffToken.js +1 -0
  42. package/lib/dsf/DsfChunk.js +1 -0
  43. package/lib/dsf/DsfParser.js +4 -2
  44. package/lib/ebml/EbmlIterator.d.ts +52 -0
  45. package/lib/ebml/EbmlIterator.js +220 -0
  46. package/lib/ebml/types.d.ts +36 -0
  47. package/lib/ebml/types.js +10 -0
  48. package/lib/flac/FlacParser.d.ts +3 -3
  49. package/lib/flac/FlacParser.js +9 -12
  50. package/lib/id3v1/ID3v1Parser.d.ts +1 -1
  51. package/lib/id3v1/ID3v1Parser.js +7 -4
  52. package/lib/id3v2/AbstractID3Parser.d.ts +1 -1
  53. package/lib/id3v2/AbstractID3Parser.js +2 -1
  54. package/lib/id3v2/FrameParser.d.ts +28 -3
  55. package/lib/id3v2/FrameParser.js +50 -28
  56. package/lib/id3v2/ID3v22TagMapper.d.ts +1 -1
  57. package/lib/id3v2/ID3v24TagMapper.d.ts +2 -1
  58. package/lib/id3v2/ID3v24TagMapper.js +23 -16
  59. package/lib/id3v2/ID3v2Parser.d.ts +2 -2
  60. package/lib/id3v2/ID3v2Parser.js +18 -8
  61. package/lib/iff/index.js +1 -0
  62. package/lib/index.d.ts +5 -6
  63. package/lib/index.js +7 -8
  64. package/lib/lyrics3/Lyrics3.d.ts +1 -1
  65. package/lib/lyrics3/Lyrics3.js +1 -1
  66. package/lib/matroska/MatroskaDtd.d.ts +2 -2
  67. package/lib/matroska/MatroskaDtd.js +247 -239
  68. package/lib/matroska/MatroskaParser.d.ts +10 -24
  69. package/lib/matroska/MatroskaParser.js +120 -205
  70. package/lib/matroska/types.d.ts +12 -46
  71. package/lib/matroska/types.js +0 -9
  72. package/lib/mp4/Atom.d.ts +3 -3
  73. package/lib/mp4/Atom.js +4 -7
  74. package/lib/mp4/AtomToken.js +2 -1
  75. package/lib/mp4/MP4Parser.js +29 -20
  76. package/lib/mp4/MP4TagMapper.d.ts +2 -2
  77. package/lib/mp4/MP4TagMapper.js +1 -1
  78. package/lib/mpeg/ExtendedLameHeader.d.ts +4 -4
  79. package/lib/mpeg/ExtendedLameHeader.js +2 -1
  80. package/lib/mpeg/MpegParser.d.ts +1 -1
  81. package/lib/mpeg/MpegParser.js +145 -96
  82. package/lib/mpeg/ReplayGainDataFormat.d.ts +1 -1
  83. package/lib/mpeg/ReplayGainDataFormat.js +1 -0
  84. package/lib/mpeg/XingTag.d.ts +4 -4
  85. package/lib/mpeg/XingTag.js +5 -4
  86. package/lib/musepack/index.js +1 -0
  87. package/lib/musepack/sv7/BitReader.js +14 -17
  88. package/lib/musepack/sv7/MpcSv7Parser.js +6 -1
  89. package/lib/musepack/sv7/StreamVersion7.js +1 -0
  90. package/lib/musepack/sv8/MpcSv8Parser.js +6 -2
  91. package/lib/musepack/sv8/StreamVersion8.d.ts +1 -1
  92. package/lib/musepack/sv8/StreamVersion8.js +1 -0
  93. package/lib/ogg/Ogg.d.ts +1 -1
  94. package/lib/ogg/Ogg.js +1 -0
  95. package/lib/ogg/OggParser.d.ts +3 -3
  96. package/lib/ogg/OggParser.js +25 -16
  97. package/lib/ogg/opus/Opus.d.ts +1 -1
  98. package/lib/ogg/opus/Opus.js +1 -0
  99. package/lib/ogg/opus/OpusParser.d.ts +4 -4
  100. package/lib/ogg/opus/OpusParser.js +2 -0
  101. package/lib/ogg/speex/Speex.js +1 -0
  102. package/lib/ogg/speex/SpeexParser.d.ts +4 -4
  103. package/lib/ogg/speex/SpeexParser.js +1 -0
  104. package/lib/ogg/theora/Theora.js +1 -0
  105. package/lib/ogg/theora/TheoraParser.d.ts +4 -4
  106. package/lib/ogg/theora/TheoraParser.js +1 -0
  107. package/lib/ogg/vorbis/Vorbis.d.ts +3 -3
  108. package/lib/ogg/vorbis/Vorbis.js +22 -11
  109. package/lib/ogg/vorbis/VorbisDecoder.d.ts +1 -1
  110. package/lib/ogg/vorbis/VorbisDecoder.js +1 -0
  111. package/lib/ogg/vorbis/VorbisParser.d.ts +4 -4
  112. package/lib/ogg/vorbis/VorbisParser.js +3 -2
  113. package/lib/ogg/vorbis/VorbisTagMapper.d.ts +2 -2
  114. package/lib/ogg/vorbis/VorbisTagMapper.js +2 -2
  115. package/lib/riff/RiffChunk.d.ts +3 -3
  116. package/lib/riff/RiffChunk.js +1 -0
  117. package/lib/riff/RiffInfoTagMap.d.ts +1 -1
  118. package/lib/type.d.ts +44 -25
  119. package/lib/wav/BwfChunk.js +1 -0
  120. package/lib/wav/WaveChunk.d.ts +1 -1
  121. package/lib/wav/WaveChunk.js +1 -0
  122. package/lib/wav/WaveParser.js +27 -17
  123. package/lib/wavpack/WavPackParser.d.ts +1 -1
  124. package/lib/wavpack/WavPackParser.js +22 -13
  125. package/lib/wavpack/WavPackToken.d.ts +13 -17
  126. package/lib/wavpack/WavPackToken.js +22 -23
  127. package/package.json +139 -150
@@ -39,7 +39,7 @@ export class CombinedTagMapper {
39
39
  if (tagMapper) {
40
40
  return this.tagMappers[tagType].mapGenericTag(tag, warnings);
41
41
  }
42
- throw new Error('No generic tag mapper defined for tag-format: ' + tagType);
42
+ throw new Error(`No generic tag mapper defined for tag-format: ${tagType}`);
43
43
  }
44
44
  registerTagMapper(genericTagMapper) {
45
45
  for (const tagType of genericTagMapper.tagTypes) {
@@ -1,4 +1,4 @@
1
- import { IToken } from 'strtok3';
1
+ import type { IToken } from 'strtok3';
2
2
  /**
3
3
  * Token for read FourCC
4
4
  * Ref: https://en.wikipedia.org/wiki/FourCC
@@ -1,6 +1,6 @@
1
- import * as generic from './GenericTagTypes.js';
2
- import { ITag } from '../type.js';
3
- import { INativeMetadataCollector, IWarningCollector } from './MetadataCollector.js';
1
+ import type * as generic from './GenericTagTypes.js';
2
+ import type { ITag } from '../type.js';
3
+ import type { INativeMetadataCollector, IWarningCollector } from './MetadataCollector.js';
4
4
  export interface IGenericTagMapper {
5
5
  /**
6
6
  * Which tagType is able to map to the generic mapping format
@@ -16,16 +16,16 @@ export interface IGenericTagMapper {
16
16
  * @param warnings Register warnings
17
17
  * @return Generic tag, if native tag could be mapped
18
18
  */
19
- mapGenericTag(tag: ITag, warnings: INativeMetadataCollector): generic.IGenericTag;
19
+ mapGenericTag(tag: ITag, warnings: INativeMetadataCollector): generic.IGenericTag | null;
20
20
  }
21
21
  export declare class CommonTagMapper implements IGenericTagMapper {
22
22
  tagTypes: generic.TagType[];
23
23
  tagMap: generic.INativeTagMap;
24
24
  static maxRatingScore: number;
25
- static toIntOrNull(str: string): number;
25
+ static toIntOrNull(str: string): number | null;
26
26
  static normalizeTrack(origVal: number | string): {
27
- no: number;
28
- of: number;
27
+ no: number | null;
28
+ of: number | null;
29
29
  };
30
30
  constructor(tagTypes: generic.TagType[], tagMap: generic.INativeTagMap);
31
31
  /**
@@ -35,7 +35,7 @@ export declare class CommonTagMapper implements IGenericTagMapper {
35
35
  * @param warnings Register warnings
36
36
  * @return common name
37
37
  */
38
- mapGenericTag(tag: ITag, warnings: IWarningCollector): generic.IGenericTag;
38
+ mapGenericTag(tag: ITag, warnings: IWarningCollector): generic.IGenericTag | null;
39
39
  /**
40
40
  * Convert native tag key to common tag key
41
41
  * @param tag Native header tag
@@ -1,7 +1,7 @@
1
1
  export class CommonTagMapper {
2
2
  static toIntOrNull(str) {
3
- const cleaned = parseInt(str, 10);
4
- return isNaN(cleaned) ? null : cleaned;
3
+ const cleaned = Number.parseInt(str, 10);
4
+ return Number.isNaN(cleaned) ? null : cleaned;
5
5
  }
6
6
  // TODO: a string of 1of1 would fail to be converted
7
7
  // converts 1/10 to no : 1, of : 10
@@ -9,8 +9,8 @@ export class CommonTagMapper {
9
9
  static normalizeTrack(origVal) {
10
10
  const split = origVal.toString().split('/');
11
11
  return {
12
- no: parseInt(split[0], 10) || null,
13
- of: parseInt(split[1], 10) || null
12
+ no: Number.parseInt(split[0], 10) || null,
13
+ of: Number.parseInt(split[1], 10) || null
14
14
  };
15
15
  }
16
16
  constructor(tagTypes, tagMap) {
@@ -1,7 +1,8 @@
1
+ import type { AnyTagValue, ICommonTagsResult } from '../type.js';
1
2
  export type TagType = 'vorbis' | 'ID3v1' | 'ID3v2.2' | 'ID3v2.3' | 'ID3v2.4' | 'APEv2' | 'asf' | 'iTunes' | 'exif' | 'matroska' | 'AIFF';
2
3
  export interface IGenericTag {
3
- id: GenericTagId;
4
- value: any;
4
+ id: keyof ICommonTagsResult;
5
+ value: AnyTagValue;
5
6
  }
6
7
  export type GenericTagId = 'track' | 'disk' | 'year' | 'title' | 'artist' | 'artists' | 'albumartist' | 'album' | 'date' | 'originaldate' | 'originalyear' | 'releasedate' | 'comment' | 'genre' | 'picture' | 'composer' | 'lyrics' | 'albumsort' | 'titlesort' | 'work' | 'artistsort' | 'albumartistsort' | 'composersort' | 'lyricist' | 'writer' | 'conductor' | 'remixer' | 'arranger' | 'engineer' | 'technician' | 'producer' | 'djmixer' | 'mixer' | 'publisher' | 'label' | 'grouping' | 'subtitle' | 'discsubtitle' | 'totaltracks' | 'totaldiscs' | 'compilation' | 'rating' | 'bpm' | 'mood' | 'media' | 'catalognumber' | 'tvShow' | 'tvShowSort' | 'tvEpisode' | 'tvEpisodeId' | 'tvNetwork' | 'tvSeason' | 'podcast' | 'podcasturl' | 'releasestatus' | 'releasetype' | 'releasecountry' | 'script' | 'language' | 'copyright' | 'license' | 'encodedby' | 'encodersettings' | 'gapless' | 'barcode' | 'isrc' | 'asin' | 'musicbrainz_recordingid' | 'musicbrainz_trackid' | 'musicbrainz_albumid' | 'musicbrainz_artistid' | 'musicbrainz_albumartistid' | 'musicbrainz_releasegroupid' | 'musicbrainz_workid' | 'musicbrainz_trmid' | 'musicbrainz_discid' | 'acoustid_id' | 'acoustid_fingerprint' | 'musicip_puid' | 'musicip_fingerprint' | 'website' | 'performer:instrument' | 'peakLevel' | 'averageLevel' | 'notes' | 'key' | 'originalalbum' | 'originalartist' | 'discogs_artist_id' | 'discogs_label_id' | 'discogs_master_release_id' | 'discogs_rating' | 'discogs_release_id' | 'discogs_votes' | 'replaygain_track_gain' | 'replaygain_track_peak' | 'replaygain_album_gain' | 'replaygain_album_peak' | 'replaygain_track_minmax' | 'replaygain_album_minmax' | 'replaygain_undo' | 'description' | 'longDescription' | 'category' | 'hdVideo' | 'keywords' | 'movement' | 'movementIndex' | 'movementTotal' | 'podcastId' | 'showMovement' | 'stik';
7
8
  export interface INativeTagMap {
@@ -25,9 +26,9 @@ export declare const commonTags: ITagInfoMap;
25
26
  * @param alias Name of common tag
26
27
  * @returns {boolean|*} true if given alias is mapped as a singleton', otherwise false
27
28
  */
28
- export declare function isSingleton(alias: GenericTagId): boolean;
29
+ export declare function isSingleton(alias: keyof ICommonTagsResult): boolean;
29
30
  /**
30
31
  * @param alias Common (generic) tag
31
32
  * @returns {boolean|*} true if given alias is a singleton or explicitly marked as unique
32
33
  */
33
- export declare function isUnique(alias: GenericTagId): boolean;
34
+ export declare function isUnique(alias: keyof ICommonTagsResult): boolean;
@@ -116,13 +116,13 @@ export const commonTags = {
116
116
  * @returns {boolean|*} true if given alias is mapped as a singleton', otherwise false
117
117
  */
118
118
  export function isSingleton(alias) {
119
- return commonTags.hasOwnProperty(alias) && !commonTags[alias].multiple;
119
+ return commonTags[alias] && !commonTags[alias].multiple;
120
120
  }
121
121
  /**
122
122
  * @param alias Common (generic) tag
123
123
  * @returns {boolean|*} true if given alias is a singleton or explicitly marked as unique
124
124
  */
125
125
  export function isUnique(alias) {
126
- return !commonTags[alias].multiple || commonTags[alias].unique;
126
+ return !commonTags[alias].multiple || commonTags[alias].unique || false;
127
127
  }
128
128
  //# sourceMappingURL=GenericTagTypes.js.map
@@ -1,5 +1,5 @@
1
- import { FormatId, IAudioMetadata, ICommonTagsResult, IFormat, INativeTags, IOptions, IQualityInformation, ITrackInfo } from '../type.js';
2
- import { IGenericTag, TagType } from './GenericTagTypes.js';
1
+ import { type FormatId, type IAudioMetadata, type ICommonTagsResult, type IFormat, type INativeTags, type IOptions, type IQualityInformation, type ITrackInfo, type AnyTagValue } from '../type.js';
2
+ import { type IGenericTag, type TagType } from './GenericTagTypes.js';
3
3
  /**
4
4
  * Combines all generic-tag-mappers for each tag type
5
5
  */
@@ -8,7 +8,7 @@ export interface IWarningCollector {
8
8
  * Register parser warning
9
9
  * @param warning
10
10
  */
11
- addWarning(warning: string): any;
11
+ addWarning(warning: string): void;
12
12
  }
13
13
  export interface INativeMetadataCollector extends IWarningCollector {
14
14
  /**
@@ -21,8 +21,8 @@ export interface INativeMetadataCollector extends IWarningCollector {
21
21
  * @returns {boolean} true if one or more tags have been found
22
22
  */
23
23
  hasAny(): boolean;
24
- setFormat(key: FormatId, value: any): void;
25
- addTag(tagType: TagType, tagId: string, value: any): Promise<void>;
24
+ setFormat(key: FormatId, value: AnyTagValue): void;
25
+ addTag(tagType: TagType, tagId: string, value: AnyTagValue): Promise<void>;
26
26
  addStreamInfo(streamInfo: ITrackInfo): void;
27
27
  }
28
28
  /**
@@ -30,7 +30,7 @@ export interface INativeMetadataCollector extends IWarningCollector {
30
30
  * Responsible for triggering async updates
31
31
  */
32
32
  export declare class MetadataCollector implements INativeMetadataCollector {
33
- private opts;
33
+ private opts?;
34
34
  readonly format: IFormat;
35
35
  readonly native: INativeTags;
36
36
  readonly common: ICommonTagsResult;
@@ -44,14 +44,14 @@ export declare class MetadataCollector implements INativeMetadataCollector {
44
44
  */
45
45
  private readonly originPriority;
46
46
  private tagMapper;
47
- constructor(opts: IOptions);
47
+ constructor(opts?: IOptions | undefined);
48
48
  /**
49
49
  * @returns {boolean} true if one or more tags have been found
50
50
  */
51
51
  hasAny(): boolean;
52
52
  addStreamInfo(streamInfo: ITrackInfo): void;
53
- setFormat(key: FormatId, value: any): void;
54
- addTag(tagType: TagType, tagId: string, value: any): Promise<void>;
53
+ setFormat(key: FormatId, value: AnyTagValue): void;
54
+ addTag(tagType: TagType, tagId: string, value: AnyTagValue): Promise<void>;
55
55
  addWarning(warning: string): void;
56
56
  postMap(tagType: TagType | 'artificial', tag: IGenericTag): Promise<void>;
57
57
  /**
@@ -22,7 +22,7 @@ export class MetadataCollector {
22
22
  this.common = {
23
23
  track: { no: null, of: null },
24
24
  disk: { no: null, of: null },
25
- movementIndex: {}
25
+ movementIndex: { no: null, of: null }
26
26
  };
27
27
  this.quality = {
28
28
  warnings: []
@@ -50,13 +50,13 @@ export class MetadataCollector {
50
50
  return Object.keys(this.native).length > 0;
51
51
  }
52
52
  addStreamInfo(streamInfo) {
53
- debug(`streamInfo: type=${TrackType[streamInfo.type]}, codec=${streamInfo.codecName}`);
53
+ debug(`streamInfo: type=${streamInfo.type ? TrackType[streamInfo.type] : '?'}, codec=${streamInfo.codecName}`);
54
54
  this.format.trackInfo.push(streamInfo);
55
55
  }
56
56
  setFormat(key, value) {
57
57
  debug(`format: ${key} = ${value}`);
58
58
  this.format[key] = value; // as any to override readonly
59
- if (this.opts.observer) {
59
+ if (this.opts?.observer) {
60
60
  this.opts.observer({ metadata: this, tag: { type: 'format', id: key, value } });
61
61
  }
62
62
  }
@@ -117,29 +117,31 @@ export class MetadataCollector {
117
117
  return;
118
118
  case 'track':
119
119
  case 'disk':
120
- case 'movementIndex':
120
+ case 'movementIndex': {
121
121
  const of = this.common[tag.id].of; // store of value, maybe maybe overwritten
122
122
  this.common[tag.id] = CommonTagMapper.normalizeTrack(tag.value);
123
123
  this.common[tag.id].of = of != null ? of : this.common[tag.id].of;
124
124
  return;
125
+ }
125
126
  case 'bpm':
126
127
  case 'year':
127
128
  case 'originalyear':
128
- tag.value = parseInt(tag.value, 10);
129
+ tag.value = Number.parseInt(tag.value, 10);
129
130
  break;
130
- case 'date':
131
+ case 'date': {
131
132
  // ToDo: be more strict on 'YYYY...'
132
- const year = parseInt(tag.value.substr(0, 4), 10);
133
- if (!isNaN(year)) {
133
+ const year = Number.parseInt(tag.value.substr(0, 4), 10);
134
+ if (!Number.isNaN(year)) {
134
135
  this.common.year = year;
135
136
  }
136
137
  break;
138
+ }
137
139
  case 'discogs_label_id':
138
140
  case 'discogs_release_id':
139
141
  case 'discogs_master_release_id':
140
142
  case 'discogs_artist_id':
141
143
  case 'discogs_votes':
142
- tag.value = typeof tag.value === 'string' ? parseInt(tag.value, 10) : tag.value;
144
+ tag.value = typeof tag.value === 'string' ? Number.parseInt(tag.value, 10) : tag.value;
143
145
  break;
144
146
  case 'replaygain_track_gain':
145
147
  case 'replaygain_track_peak':
@@ -148,25 +150,28 @@ export class MetadataCollector {
148
150
  tag.value = toRatio(tag.value);
149
151
  break;
150
152
  case 'replaygain_track_minmax':
151
- tag.value = tag.value.split(',').map(v => parseInt(v, 10));
153
+ tag.value = tag.value.split(',').map(v => Number.parseInt(v, 10));
152
154
  break;
153
- case 'replaygain_undo':
154
- const minMix = tag.value.split(',').map(v => parseInt(v, 10));
155
+ case 'replaygain_undo': {
156
+ const minMix = tag.value.split(',').map(v => Number.parseInt(v, 10));
155
157
  tag.value = {
156
158
  leftChannel: minMix[0],
157
159
  rightChannel: minMix[1]
158
160
  };
159
161
  break;
162
+ }
160
163
  case 'gapless': // iTunes gap-less flag
161
164
  case 'compilation':
162
165
  case 'podcast':
163
166
  case 'showMovement':
164
167
  tag.value = tag.value === '1' || tag.value === 1; // boolean
165
168
  break;
166
- case 'isrc': // Only keep unique values
167
- if (this.common[tag.id] && this.common[tag.id].indexOf(tag.value) !== -1)
169
+ case 'isrc': { // Only keep unique values
170
+ const commonTag = this.common[tag.id];
171
+ if (commonTag && commonTag.indexOf(tag.value) !== -1)
168
172
  return;
169
173
  break;
174
+ }
170
175
  case 'comment':
171
176
  if (typeof tag.value === 'string') {
172
177
  tag.value = { text: tag.value };
@@ -216,7 +221,7 @@ export class MetadataCollector {
216
221
  }
217
222
  return picture;
218
223
  }
219
- this.addWarning(`Empty picture tag found`);
224
+ this.addWarning("Empty picture tag found");
220
225
  return null;
221
226
  }
222
227
  /**
@@ -263,7 +268,7 @@ export class MetadataCollector {
263
268
  return debug(`Ignore native tag (list): ${tagType}.${tag.id} = ${tag.value}`);
264
269
  }
265
270
  }
266
- if (this.opts.observer) {
271
+ if (this.opts?.observer) {
267
272
  this.opts.observer({ metadata: this, tag: { type: 'common', id: tag.id, value: tag.value } });
268
273
  }
269
274
  // ToDo: trigger metadata event
@@ -271,7 +276,7 @@ export class MetadataCollector {
271
276
  }
272
277
  export function joinArtists(artists) {
273
278
  if (artists.length > 2) {
274
- return artists.slice(0, artists.length - 1).join(', ') + ' & ' + artists[artists.length - 1];
279
+ return `${artists.slice(0, artists.length - 1).join(', ')} & ${artists[artists.length - 1]}`;
275
280
  }
276
281
  return artists.join(' & ');
277
282
  }
@@ -1,4 +1,4 @@
1
- import { IRandomReader } from '../type.js';
1
+ import type { IRandomReader } from '../type.js';
2
2
  /**
3
3
  * Provides abstract file access via the IRandomRead interface
4
4
  */
@@ -1,4 +1,4 @@
1
- import * as fs from 'fs';
1
+ import * as fs from 'node:fs';
2
2
  /**
3
3
  * Provides abstract file access via the IRandomRead interface
4
4
  */
@@ -1,4 +1,4 @@
1
- import { IRandomReader } from '../type.js';
1
+ import type { IRandomReader } from '../type.js';
2
2
  /**
3
3
  * Provides abstract Uint8Array access via the IRandomRead interface
4
4
  */
@@ -1,9 +1,5 @@
1
- import { IRatio } from '../type.js';
1
+ import type { IRatio } from '../type.js';
2
2
  export type StringEncoding = 'ascii' | 'utf8' | 'utf-16le' | 'ucs2' | 'base64url' | 'latin1' | 'hex';
3
- export interface ITextEncoding {
4
- encoding: StringEncoding;
5
- bom?: boolean;
6
- }
7
3
  export declare function getBit(buf: Uint8Array, off: number, bit: number): boolean;
8
4
  /**
9
5
  * Found delimiting zero in uint8Array
@@ -54,4 +50,4 @@ export declare function dbToRatio(dB: number): number;
54
50
  * Convert replay gain to ratio and Decibel
55
51
  * @param value string holding a ratio like '0.034' or '-7.54 dB'
56
52
  */
57
- export declare function toRatio(value: string): IRatio;
53
+ export declare function toRatio(value: string): IRatio | undefined;
@@ -20,14 +20,12 @@ export function findZero(uint8Array, start, end, encoding) {
20
20
  }
21
21
  return i;
22
22
  }
23
- else {
24
- while (uint8Array[i] !== 0) {
25
- if (i >= end)
26
- return end;
27
- i++;
28
- }
29
- return i;
23
+ while (uint8Array[i] !== 0) {
24
+ if (i >= end)
25
+ return end;
26
+ i++;
30
27
  }
28
+ return i;
31
29
  }
32
30
  export function trimRightNull(x) {
33
31
  const pos0 = x.indexOf('\0');
@@ -53,7 +51,7 @@ export function decodeString(uint8Array, encoding) {
53
51
  if (uint8Array[0] === 0xFF && uint8Array[1] === 0xFE) { // little endian
54
52
  return decodeString(uint8Array.subarray(2), encoding);
55
53
  }
56
- else if (encoding === 'utf-16le' && uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) {
54
+ if (encoding === 'utf-16le' && uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) {
57
55
  // BOM, indicating big endian decoding
58
56
  if ((uint8Array.length & 1) !== 0)
59
57
  throw new Error('Expected even number of octets for 16-bit unicode string');
@@ -106,7 +104,7 @@ export function a2hex(str) {
106
104
  const arr = [];
107
105
  for (let i = 0, l = str.length; i < l; i++) {
108
106
  const hex = Number(str.charCodeAt(i)).toString(16);
109
- arr.push(hex.length === 1 ? '0' + hex : hex);
107
+ arr.push(hex.length === 1 ? `0${hex}` : hex);
110
108
  }
111
109
  return arr.join(' ');
112
110
  }
@@ -122,7 +120,7 @@ export function ratioToDb(ratio) {
122
120
  * db Decibels
123
121
  */
124
122
  export function dbToRatio(dB) {
125
- return Math.pow(10, dB / 10);
123
+ return 10 ** (dB / 10);
126
124
  }
127
125
  /**
128
126
  * Convert replay gain to ratio and Decibel
@@ -132,7 +130,7 @@ export function toRatio(value) {
132
130
  const ps = value.split(' ').map(p => p.trim().toLowerCase());
133
131
  // @ts-ignore
134
132
  if (ps.length >= 1) {
135
- const v = parseFloat(ps[0]);
133
+ const v = Number.parseFloat(ps[0]);
136
134
  return ps.length === 2 && ps[1] === 'db' ? {
137
135
  dB: v,
138
136
  ratio: dbToRatio(v)
package/lib/core.d.ts CHANGED
@@ -1,12 +1,10 @@
1
1
  /**
2
2
  * Primary entry point, Node.js specific entry point is index.ts
3
3
  */
4
- import * as strtok3 from 'strtok3';
4
+ import { type AnyWebByteStream, type IFileInfo, type ITokenizer } from 'strtok3';
5
5
  import type { IAudioMetadata, INativeTagDict, IOptions, IPicture, IPrivateOptions, IRandomReader, ITag } from './type.js';
6
- import type { ReadableStream as NodeReadableStream } from 'node:stream/web';
7
- export { IFileInfo } from 'strtok3';
8
- export { IAudioMetadata, IOptions, ITag, INativeTagDict, ICommonTagsResult, IFormat, IPicture, IRatio, IChapter, ILyricsTag, LyricsContentType, TimestampFormat } from './type.js';
9
- export type AnyWebStream<G> = NodeReadableStream<G> | ReadableStream<G>;
6
+ export type { IFileInfo } from 'strtok3';
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';
10
8
  /**
11
9
  * Parse Web API File
12
10
  * Requires Blob to be able to stream using a ReadableStreamBYOBReader, only available since Node.js ≥ 20
@@ -22,7 +20,7 @@ export declare function parseBlob(blob: Blob, options?: IOptions): Promise<IAudi
22
20
  * @param fileInfo - File information object or MIME-type string
23
21
  * @returns Metadata
24
22
  */
25
- export declare function parseWebStream(webStream: AnyWebStream<Uint8Array>, fileInfo?: strtok3.IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
23
+ export declare function parseWebStream(webStream: AnyWebByteStream, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
26
24
  /**
27
25
  * Parse audio from Node Buffer
28
26
  * @param uint8Array - Uint8Array holding audio data
@@ -31,14 +29,14 @@ export declare function parseWebStream(webStream: AnyWebStream<Uint8Array>, file
31
29
  * @returns Metadata
32
30
  * Ref: https://github.com/Borewit/strtok3/blob/e6938c81ff685074d5eb3064a11c0b03ca934c1d/src/index.ts#L15
33
31
  */
34
- export declare function parseBuffer(uint8Array: Uint8Array, fileInfo?: strtok3.IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
32
+ export declare function parseBuffer(uint8Array: Uint8Array, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
35
33
  /**
36
34
  * Parse audio from ITokenizer source
37
35
  * @param tokenizer - Audio source implementing the tokenizer interface
38
36
  * @param options - Parsing options
39
37
  * @returns Metadata
40
38
  */
41
- export declare function parseFromTokenizer(tokenizer: strtok3.ITokenizer, options?: IOptions): Promise<IAudioMetadata>;
39
+ export declare function parseFromTokenizer(tokenizer: ITokenizer, options?: IOptions): Promise<IAudioMetadata>;
42
40
  /**
43
41
  * Create a dictionary ordered by their tag id (key)
44
42
  * @param nativeTags list of tags
@@ -50,7 +48,7 @@ export declare function orderTags(nativeTags: ITag[]): INativeTagDict;
50
48
  * @param rating Normalized rating [0..1] (common.rating[n].rating)
51
49
  * @returns Number of stars: 1, 2, 3, 4 or 5 stars
52
50
  */
53
- export declare function ratingToStars(rating: number): number;
51
+ export declare function ratingToStars(rating: number | undefined): number;
54
52
  /**
55
53
  * Select most likely cover image.
56
54
  * @param pictures Usually metadata.common.picture
package/lib/core.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Primary entry point, Node.js specific entry point is index.ts
3
3
  */
4
- import * as strtok3 from 'strtok3';
5
- import { ParserFactory } from './ParserFactory.js';
4
+ import { fromWebStream, fromBuffer } from 'strtok3';
5
+ import { parseOnContentType } from './ParserFactory.js';
6
6
  import { RandomUint8ArrayReader } from './common/RandomUint8ArrayReader.js';
7
7
  import { APEv2Parser } from './apev2/APEv2Parser.js';
8
8
  import { hasID3v1Header } from './id3v1/ID3v1Parser.js';
@@ -30,7 +30,7 @@ export async function parseBlob(blob, options = {}) {
30
30
  * @returns Metadata
31
31
  */
32
32
  export function parseWebStream(webStream, fileInfo, options = {}) {
33
- return parseFromTokenizer(strtok3.fromWebStream(webStream, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo }), options);
33
+ return parseFromTokenizer(fromWebStream(webStream, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo }), options);
34
34
  }
35
35
  /**
36
36
  * Parse audio from Node Buffer
@@ -43,7 +43,7 @@ export function parseWebStream(webStream, fileInfo, options = {}) {
43
43
  export async function parseBuffer(uint8Array, fileInfo, options = {}) {
44
44
  const bufferReader = new RandomUint8ArrayReader(uint8Array);
45
45
  await scanAppendingHeaders(bufferReader, options);
46
- const tokenizer = strtok3.fromBuffer(uint8Array, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo });
46
+ const tokenizer = fromBuffer(uint8Array, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo });
47
47
  return parseFromTokenizer(tokenizer, options);
48
48
  }
49
49
  /**
@@ -53,7 +53,7 @@ export async function parseBuffer(uint8Array, fileInfo, options = {}) {
53
53
  * @returns Metadata
54
54
  */
55
55
  export function parseFromTokenizer(tokenizer, options) {
56
- return ParserFactory.parseOnContentType(tokenizer, options);
56
+ return parseOnContentType(tokenizer, options);
57
57
  }
58
58
  /**
59
59
  * Create a dictionary ordered by their tag id (key)
@@ -62,8 +62,11 @@ export function parseFromTokenizer(tokenizer, options) {
62
62
  */
63
63
  export function orderTags(nativeTags) {
64
64
  const tags = {};
65
- for (const tag of nativeTags) {
66
- (tags[tag.id] = (tags[tag.id] || [])).push(tag.value);
65
+ for (const { id, value } of nativeTags) {
66
+ if (!tags[id]) {
67
+ tags[id] = [];
68
+ }
69
+ tags[id].push(value);
67
70
  }
68
71
  return tags;
69
72
  }
@@ -24,7 +24,7 @@ export class DsdiffParser extends BasicParser {
24
24
  this.metadata.setFormat('lossless', true);
25
25
  return this.readFmt8Chunks(header.chunkSize - BigInt(FourCcToken.len));
26
26
  default:
27
- throw Error(`Unsupported DSDIFF type: ${type}`);
27
+ throw new Error(`Unsupported DSDIFF type: ${type}`);
28
28
  }
29
29
  }
30
30
  async readFmt8Chunks(remainingSize) {
@@ -40,28 +40,35 @@ export class DsdiffParser extends BasicParser {
40
40
  debug(`Reading data of chunk[ID=${header.chunkID}, size=${header.chunkSize}]`);
41
41
  const p0 = this.tokenizer.position;
42
42
  switch (header.chunkID.trim()) {
43
- case 'FVER': // 3.1 FORMAT VERSION CHUNK
43
+ case 'FVER': { // 3.1 FORMAT VERSION CHUNK
44
44
  const version = await this.tokenizer.readToken(Token.UINT32_LE);
45
45
  debug(`DSDIFF version=${version}`);
46
46
  break;
47
- case 'PROP': // 3.2 PROPERTY CHUNK
47
+ }
48
+ case 'PROP': { // 3.2 PROPERTY CHUNK
48
49
  const propType = await this.tokenizer.readToken(FourCcToken);
49
50
  if (propType !== 'SND ')
50
51
  throw new Error('Unexpected PROP-chunk ID');
51
52
  await this.handleSoundPropertyChunks(header.chunkSize - BigInt(FourCcToken.len));
52
53
  break;
53
- case 'ID3': // Unofficial ID3 tag support
54
+ }
55
+ case 'ID3': { // Unofficial ID3 tag support
54
56
  const id3_data = await this.tokenizer.readToken(new Token.Uint8ArrayType(Number(header.chunkSize)));
55
57
  const rst = strtok3.fromBuffer(id3_data);
56
58
  await new ID3v2Parser().parse(this.metadata, rst, this.options);
57
59
  break;
60
+ }
61
+ case 'DSD':
62
+ if (this.metadata.format.numberOfChannels) {
63
+ this.metadata.setFormat('numberOfSamples', Number(header.chunkSize * BigInt(8) / BigInt(this.metadata.format.numberOfChannels)));
64
+ }
65
+ if (this.metadata.format.numberOfSamples && this.metadata.format.sampleRate) {
66
+ this.metadata.setFormat('duration', this.metadata.format.numberOfSamples / this.metadata.format.sampleRate);
67
+ }
68
+ break;
58
69
  default:
59
70
  debug(`Ignore chunk[ID=${header.chunkID}, size=${header.chunkSize}]`);
60
71
  break;
61
- case 'DSD':
62
- this.metadata.setFormat('numberOfSamples', Number(header.chunkSize * BigInt(8) / BigInt(this.metadata.format.numberOfChannels)));
63
- this.metadata.setFormat('duration', this.metadata.format.numberOfSamples / this.metadata.format.sampleRate);
64
- break;
65
72
  }
66
73
  const remaining = header.chunkSize - BigInt(this.tokenizer.position - p0);
67
74
  if (remaining > 0) {
@@ -76,16 +83,18 @@ export class DsdiffParser extends BasicParser {
76
83
  debug(`Sound-property-chunk[ID=${sndPropHeader.chunkID}, size=${sndPropHeader.chunkSize}]`);
77
84
  const p0 = this.tokenizer.position;
78
85
  switch (sndPropHeader.chunkID.trim()) {
79
- case 'FS': // 3.2.1 Sample Rate Chunk
86
+ case 'FS': { // 3.2.1 Sample Rate Chunk
80
87
  const sampleRate = await this.tokenizer.readToken(Token.UINT32_BE);
81
88
  this.metadata.setFormat('sampleRate', sampleRate);
82
89
  break;
83
- case 'CHNL': // 3.2.2 Channels Chunk
90
+ }
91
+ case 'CHNL': { // 3.2.2 Channels Chunk
84
92
  const numChannels = await this.tokenizer.readToken(Token.UINT16_BE);
85
93
  this.metadata.setFormat('numberOfChannels', numChannels);
86
94
  await this.handleChannelChunks(sndPropHeader.chunkSize - BigInt(Token.UINT16_BE.len));
87
95
  break;
88
- case 'CMPR': // 3.2.3 Compression Type Chunk
96
+ }
97
+ case 'CMPR': { // 3.2.3 Compression Type Chunk
89
98
  const compressionIdCode = (await this.tokenizer.readToken(FourCcToken)).trim();
90
99
  const count = await this.tokenizer.readToken(Token.UINT8);
91
100
  const compressionName = await this.tokenizer.readToken(new Token.StringType(count, 'ascii'));
@@ -95,18 +104,20 @@ export class DsdiffParser extends BasicParser {
95
104
  }
96
105
  this.metadata.setFormat('codec', `${compressionIdCode} (${compressionName})`);
97
106
  break;
98
- case 'ABSS': // 3.2.4 Absolute Start Time Chunk
107
+ }
108
+ case 'ABSS': { // 3.2.4 Absolute Start Time Chunk
99
109
  const hours = await this.tokenizer.readToken(Token.UINT16_BE);
100
110
  const minutes = await this.tokenizer.readToken(Token.UINT8);
101
111
  const seconds = await this.tokenizer.readToken(Token.UINT8);
102
112
  const samples = await this.tokenizer.readToken(Token.UINT32_BE);
103
113
  debug(`ABSS ${hours}:${minutes}:${seconds}.${samples}`);
104
114
  break;
105
- case 'LSCO': // 3.2.5 Loudspeaker Configuration Chunk
115
+ }
116
+ case 'LSCO': { // 3.2.5 Loudspeaker Configuration Chunk
106
117
  const lsConfig = await this.tokenizer.readToken(Token.UINT16_BE);
107
118
  debug(`LSCO lsConfig=${lsConfig}`);
108
119
  break;
109
- case 'COMT':
120
+ }
110
121
  default:
111
122
  debug(`Unknown sound-property-chunk[ID=${sndPropHeader.chunkID}, size=${sndPropHeader.chunkSize}]`);
112
123
  await this.tokenizer.ignore(Number(sndPropHeader.chunkSize));
@@ -137,3 +148,4 @@ export class DsdiffParser extends BasicParser {
137
148
  return channels;
138
149
  }
139
150
  }
151
+ //# sourceMappingURL=DsdiffParser.js.map
@@ -1,6 +1,6 @@
1
1
  import type { IGetToken } from 'strtok3';
2
- import { IChunkHeader64 } from '../iff/index.js';
3
- export { IChunkHeader64 } from '../iff/index.js';
2
+ import type { IChunkHeader64 } from '../iff/index.js';
3
+ export { type IChunkHeader64 } from '../iff/index.js';
4
4
  /**
5
5
  * DSDIFF chunk header
6
6
  * The data-size encoding is deviating from EA-IFF 85
@@ -16,3 +16,4 @@ export const ChunkHeader64 = {
16
16
  };
17
17
  }
18
18
  };
19
+ //# sourceMappingURL=DsdiffToken.js.map
@@ -49,3 +49,4 @@ export const FormatChunk = {
49
49
  };
50
50
  }
51
51
  };
52
+ //# sourceMappingURL=DsfChunk.js.map