music-metadata 7.11.7 → 7.12.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 (155) hide show
  1. package/LICENSE.txt +9 -0
  2. package/README.md +434 -432
  3. package/lib/ParserFactory.d.ts +48 -49
  4. package/lib/ParserFactory.js +252 -251
  5. package/lib/aiff/AiffParser.d.ts +14 -15
  6. package/lib/aiff/AiffParser.js +84 -85
  7. package/lib/aiff/AiffToken.d.ts +22 -22
  8. package/lib/aiff/AiffToken.js +43 -43
  9. package/lib/apev2/APEv2Parser.d.ts +30 -30
  10. package/lib/apev2/APEv2Parser.js +161 -162
  11. package/lib/apev2/APEv2TagMapper.d.ts +4 -4
  12. package/lib/apev2/APEv2TagMapper.js +86 -86
  13. package/lib/apev2/APEv2Token.d.ts +100 -100
  14. package/lib/apev2/APEv2Token.js +126 -126
  15. package/lib/asf/AsfObject.d.ts +319 -319
  16. package/lib/asf/AsfObject.js +384 -384
  17. package/lib/asf/AsfParser.d.ts +17 -17
  18. package/lib/asf/AsfParser.js +135 -135
  19. package/lib/asf/AsfTagMapper.d.ts +7 -7
  20. package/lib/asf/AsfTagMapper.js +95 -95
  21. package/lib/asf/AsfUtil.d.ts +13 -13
  22. package/lib/asf/AsfUtil.js +40 -40
  23. package/lib/asf/GUID.d.ts +84 -86
  24. package/lib/asf/GUID.js +121 -123
  25. package/lib/common/BasicParser.d.ts +17 -17
  26. package/lib/common/BasicParser.js +18 -18
  27. package/lib/common/CaseInsensitiveTagMap.d.ts +10 -10
  28. package/lib/common/CaseInsensitiveTagMap.js +21 -21
  29. package/lib/common/CombinedTagMapper.d.ts +19 -19
  30. package/lib/common/CombinedTagMapper.js +51 -51
  31. package/lib/common/FourCC.d.ts +6 -6
  32. package/lib/common/FourCC.js +28 -28
  33. package/lib/common/GenericTagMapper.d.ts +51 -51
  34. package/lib/common/GenericTagMapper.js +55 -55
  35. package/lib/common/GenericTagTypes.d.ts +33 -33
  36. package/lib/common/GenericTagTypes.js +131 -131
  37. package/lib/common/MetadataCollector.d.ts +76 -76
  38. package/lib/common/MetadataCollector.js +275 -275
  39. package/lib/common/RandomFileReader.d.ts +22 -20
  40. package/lib/common/RandomFileReader.js +34 -37
  41. package/lib/common/RandomUint8ArrayReader.d.ts +18 -18
  42. package/lib/common/RandomUint8ArrayReader.js +25 -25
  43. package/lib/common/Util.d.ts +57 -58
  44. package/lib/common/Util.js +157 -162
  45. package/lib/core.d.ts +48 -48
  46. package/lib/core.js +90 -90
  47. package/lib/dsdiff/DsdiffParser.d.ts +14 -14
  48. package/lib/dsdiff/DsdiffParser.js +143 -143
  49. package/lib/dsdiff/DsdiffToken.d.ts +9 -9
  50. package/lib/dsdiff/DsdiffToken.js +21 -21
  51. package/lib/dsf/DsfChunk.d.ts +86 -86
  52. package/lib/dsf/DsfChunk.js +54 -54
  53. package/lib/dsf/DsfParser.d.ts +9 -9
  54. package/lib/dsf/DsfParser.js +56 -56
  55. package/lib/flac/FlacParser.d.ts +28 -28
  56. package/lib/flac/FlacParser.js +175 -175
  57. package/lib/id3v1/ID3v1Parser.d.ts +13 -13
  58. package/lib/id3v1/ID3v1Parser.js +134 -134
  59. package/lib/id3v1/ID3v1TagMap.d.ts +4 -4
  60. package/lib/id3v1/ID3v1TagMap.js +22 -22
  61. package/lib/id3v2/AbstractID3Parser.d.ts +17 -17
  62. package/lib/id3v2/AbstractID3Parser.js +60 -60
  63. package/lib/id3v2/FrameParser.d.ts +32 -32
  64. package/lib/id3v2/FrameParser.js +329 -329
  65. package/lib/id3v2/ID3v22TagMapper.d.ts +9 -9
  66. package/lib/id3v2/ID3v22TagMapper.js +55 -55
  67. package/lib/id3v2/ID3v24TagMapper.d.ts +14 -14
  68. package/lib/id3v2/ID3v24TagMapper.js +193 -193
  69. package/lib/id3v2/ID3v2Parser.d.ts +29 -29
  70. package/lib/id3v2/ID3v2Parser.js +184 -194
  71. package/lib/id3v2/ID3v2Token.d.ts +73 -73
  72. package/lib/id3v2/ID3v2Token.js +106 -106
  73. package/lib/iff/index.d.ts +33 -33
  74. package/lib/iff/index.js +19 -19
  75. package/lib/index.d.ts +45 -45
  76. package/lib/index.js +74 -74
  77. package/lib/lyrics3/Lyrics3.d.ts +3 -3
  78. package/lib/lyrics3/Lyrics3.js +17 -17
  79. package/lib/matroska/MatroskaDtd.d.ts +8 -8
  80. package/lib/matroska/MatroskaDtd.js +279 -279
  81. package/lib/matroska/MatroskaParser.d.ts +37 -37
  82. package/lib/matroska/MatroskaParser.js +235 -235
  83. package/lib/matroska/MatroskaTagMapper.d.ts +4 -4
  84. package/lib/matroska/MatroskaTagMapper.js +35 -35
  85. package/lib/matroska/types.d.ts +175 -175
  86. package/lib/matroska/types.js +33 -32
  87. package/lib/mp4/Atom.d.ts +16 -16
  88. package/lib/mp4/Atom.js +70 -70
  89. package/lib/mp4/AtomToken.d.ts +395 -395
  90. package/lib/mp4/AtomToken.js +406 -406
  91. package/lib/mp4/MP4Parser.d.ts +30 -30
  92. package/lib/mp4/MP4Parser.js +511 -511
  93. package/lib/mp4/MP4TagMapper.d.ts +5 -5
  94. package/lib/mp4/MP4TagMapper.js +115 -115
  95. package/lib/mpeg/ExtendedLameHeader.d.ts +27 -27
  96. package/lib/mpeg/ExtendedLameHeader.js +31 -31
  97. package/lib/mpeg/MpegParser.d.ts +49 -49
  98. package/lib/mpeg/MpegParser.js +524 -529
  99. package/lib/mpeg/ReplayGainDataFormat.d.ts +55 -55
  100. package/lib/mpeg/ReplayGainDataFormat.js +69 -69
  101. package/lib/mpeg/XingTag.d.ts +45 -45
  102. package/lib/mpeg/XingTag.js +69 -69
  103. package/lib/musepack/index.d.ts +5 -5
  104. package/lib/musepack/index.js +32 -32
  105. package/lib/musepack/sv7/BitReader.d.ts +13 -13
  106. package/lib/musepack/sv7/BitReader.js +54 -54
  107. package/lib/musepack/sv7/MpcSv7Parser.d.ts +8 -8
  108. package/lib/musepack/sv7/MpcSv7Parser.js +46 -46
  109. package/lib/musepack/sv7/StreamVersion7.d.ts +28 -28
  110. package/lib/musepack/sv7/StreamVersion7.js +41 -41
  111. package/lib/musepack/sv8/MpcSv8Parser.d.ts +6 -6
  112. package/lib/musepack/sv8/MpcSv8Parser.js +55 -55
  113. package/lib/musepack/sv8/StreamVersion8.d.ts +40 -40
  114. package/lib/musepack/sv8/StreamVersion8.js +80 -80
  115. package/lib/ogg/Ogg.d.ts +72 -72
  116. package/lib/ogg/Ogg.js +2 -2
  117. package/lib/ogg/OggParser.d.ts +23 -23
  118. package/lib/ogg/OggParser.js +126 -126
  119. package/lib/ogg/opus/Opus.d.ts +48 -48
  120. package/lib/ogg/opus/Opus.js +28 -28
  121. package/lib/ogg/opus/OpusParser.d.ts +25 -25
  122. package/lib/ogg/opus/OpusParser.js +56 -56
  123. package/lib/ogg/speex/Speex.d.ts +36 -36
  124. package/lib/ogg/speex/Speex.js +31 -31
  125. package/lib/ogg/speex/SpeexParser.d.ts +22 -22
  126. package/lib/ogg/speex/SpeexParser.js +35 -35
  127. package/lib/ogg/theora/Theora.d.ts +20 -20
  128. package/lib/ogg/theora/Theora.js +23 -23
  129. package/lib/ogg/theora/TheoraParser.d.ts +28 -28
  130. package/lib/ogg/theora/TheoraParser.js +44 -44
  131. package/lib/ogg/vorbis/Vorbis.d.ts +69 -79
  132. package/lib/ogg/vorbis/Vorbis.js +78 -78
  133. package/lib/ogg/vorbis/VorbisDecoder.d.ts +12 -12
  134. package/lib/ogg/vorbis/VorbisDecoder.js +32 -32
  135. package/lib/ogg/vorbis/VorbisParser.d.ts +36 -36
  136. package/lib/ogg/vorbis/VorbisParser.js +128 -128
  137. package/lib/ogg/vorbis/VorbisTagMapper.d.ts +7 -7
  138. package/lib/ogg/vorbis/VorbisTagMapper.js +132 -132
  139. package/lib/riff/RiffChunk.d.ts +16 -16
  140. package/lib/riff/RiffChunk.js +32 -32
  141. package/lib/riff/RiffInfoTagMap.d.ts +10 -10
  142. package/lib/riff/RiffInfoTagMap.js +37 -37
  143. package/lib/type.d.ts +592 -599
  144. package/lib/type.js +5 -13
  145. package/lib/wav/BwfChunk.d.ts +17 -0
  146. package/lib/wav/BwfChunk.js +28 -0
  147. package/lib/wav/WaveChunk.d.ts +64 -64
  148. package/lib/wav/WaveChunk.js +65 -65
  149. package/lib/wav/WaveParser.d.ts +24 -24
  150. package/lib/wav/WaveParser.js +156 -144
  151. package/lib/wavpack/WavPackParser.d.ts +14 -14
  152. package/lib/wavpack/WavPackParser.js +99 -105
  153. package/lib/wavpack/WavPackToken.d.ts +64 -64
  154. package/lib/wavpack/WavPackToken.js +76 -76
  155. package/package.json +150 -142
@@ -1,276 +1,276 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.joinArtists = exports.MetadataCollector = void 0;
4
- const type_1 = require("../type");
5
- const _debug = require("debug");
6
- const GenericTagTypes_1 = require("./GenericTagTypes");
7
- const CombinedTagMapper_1 = require("./CombinedTagMapper");
8
- const GenericTagMapper_1 = require("./GenericTagMapper");
9
- const Util_1 = require("./Util");
10
- const FileType = require("file-type/core");
11
- const debug = _debug('music-metadata:collector');
12
- const TagPriority = ['matroska', 'APEv2', 'vorbis', 'ID3v2.4', 'ID3v2.3', 'ID3v2.2', 'exif', 'asf', 'iTunes', 'ID3v1'];
13
- /**
14
- * Provided to the parser to uodate the metadata result.
15
- * Responsible for triggering async updates
16
- */
17
- class MetadataCollector {
18
- constructor(opts) {
19
- this.opts = opts;
20
- this.format = {
21
- tagTypes: [],
22
- trackInfo: []
23
- };
24
- this.native = {};
25
- this.common = {
26
- track: { no: null, of: null },
27
- disk: { no: null, of: null },
28
- movementIndex: {}
29
- };
30
- this.quality = {
31
- warnings: []
32
- };
33
- /**
34
- * Keeps track of origin priority for each mapped id
35
- */
36
- this.commonOrigin = {};
37
- /**
38
- * Maps a tag type to a priority
39
- */
40
- this.originPriority = {};
41
- this.tagMapper = new CombinedTagMapper_1.CombinedTagMapper();
42
- let priority = 1;
43
- for (const tagType of TagPriority) {
44
- this.originPriority[tagType] = priority++;
45
- }
46
- this.originPriority.artificial = 500; // Filled using alternative tags
47
- this.originPriority.id3v1 = 600; // Consider worst due to field length limit
48
- }
49
- /**
50
- * @returns {boolean} true if one or more tags have been found
51
- */
52
- hasAny() {
53
- return Object.keys(this.native).length > 0;
54
- }
55
- addStreamInfo(streamInfo) {
56
- debug(`streamInfo: type=${type_1.TrackType[streamInfo.type]}, codec=${streamInfo.codecName}`);
57
- this.format.trackInfo.push(streamInfo);
58
- }
59
- setFormat(key, value) {
60
- debug(`format: ${key} = ${value}`);
61
- this.format[key] = value; // as any to override readonly
62
- if (this.opts.observer) {
63
- this.opts.observer({ metadata: this, tag: { type: 'format', id: key, value } });
64
- }
65
- }
66
- addTag(tagType, tagId, value) {
67
- debug(`tag ${tagType}.${tagId} = ${value}`);
68
- if (!this.native[tagType]) {
69
- this.format.tagTypes.push(tagType);
70
- this.native[tagType] = [];
71
- }
72
- this.native[tagType].push({ id: tagId, value });
73
- this.toCommon(tagType, tagId, value);
74
- }
75
- addWarning(warning) {
76
- this.quality.warnings.push({ message: warning });
77
- }
78
- postMap(tagType, tag) {
79
- // Common tag (alias) found
80
- // check if we need to do something special with common tag
81
- // if the event has been aliased then we need to clean it before
82
- // it is emitted to the user. e.g. genre (20) -> Electronic
83
- switch (tag.id) {
84
- case 'artist':
85
- if (this.commonOrigin.artist === this.originPriority[tagType]) {
86
- // Assume the artist field is used as artists
87
- return this.postMap('artificial', { id: 'artists', value: tag.value });
88
- }
89
- if (!this.common.artists) {
90
- // Fill artists using artist source
91
- this.setGenericTag('artificial', { id: 'artists', value: tag.value });
92
- }
93
- break;
94
- case 'artists':
95
- if (!this.common.artist || this.commonOrigin.artist === this.originPriority.artificial) {
96
- if (!this.common.artists || this.common.artists.indexOf(tag.value) === -1) {
97
- // Fill artist using artists source
98
- const artists = (this.common.artists || []).concat([tag.value]);
99
- const value = joinArtists(artists);
100
- const artistTag = { id: 'artist', value };
101
- this.setGenericTag('artificial', artistTag);
102
- }
103
- }
104
- break;
105
- case 'picture':
106
- this.postFixPicture(tag.value).then(picture => {
107
- if (picture !== null) {
108
- tag.value = picture;
109
- this.setGenericTag(tagType, tag);
110
- }
111
- });
112
- return;
113
- case 'totaltracks':
114
- this.common.track.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value);
115
- return;
116
- case 'totaldiscs':
117
- this.common.disk.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value);
118
- return;
119
- case 'movementTotal':
120
- this.common.movementIndex.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value);
121
- return;
122
- case 'track':
123
- case 'disk':
124
- case 'movementIndex':
125
- const of = this.common[tag.id].of; // store of value, maybe maybe overwritten
126
- this.common[tag.id] = GenericTagMapper_1.CommonTagMapper.normalizeTrack(tag.value);
127
- this.common[tag.id].of = of != null ? of : this.common[tag.id].of;
128
- return;
129
- case 'bpm':
130
- case 'year':
131
- case 'originalyear':
132
- tag.value = parseInt(tag.value, 10);
133
- break;
134
- case 'date':
135
- // ToDo: be more strict on 'YYYY...'
136
- const year = parseInt(tag.value.substr(0, 4), 10);
137
- if (!isNaN(year)) {
138
- this.common.year = year;
139
- }
140
- break;
141
- case 'discogs_label_id':
142
- case 'discogs_release_id':
143
- case 'discogs_master_release_id':
144
- case 'discogs_artist_id':
145
- case 'discogs_votes':
146
- tag.value = typeof tag.value === 'string' ? parseInt(tag.value, 10) : tag.value;
147
- break;
148
- case 'replaygain_track_gain':
149
- case 'replaygain_track_peak':
150
- case 'replaygain_album_gain':
151
- case 'replaygain_album_peak':
152
- tag.value = (0, Util_1.toRatio)(tag.value);
153
- break;
154
- case 'replaygain_track_minmax':
155
- tag.value = tag.value.split(',').map(v => parseInt(v, 10));
156
- break;
157
- case 'replaygain_undo':
158
- const minMix = tag.value.split(',').map(v => parseInt(v, 10));
159
- tag.value = {
160
- leftChannel: minMix[0],
161
- rightChannel: minMix[1]
162
- };
163
- break;
164
- case 'gapless': // iTunes gap-less flag
165
- case 'compilation':
166
- case 'podcast':
167
- case 'showMovement':
168
- tag.value = tag.value === '1' || tag.value === 1; // boolean
169
- break;
170
- case 'isrc': // Only keep unique values
171
- if (this.common[tag.id] && this.common[tag.id].indexOf(tag.value) !== -1)
172
- return;
173
- break;
174
- default:
175
- // nothing to do
176
- }
177
- if (tag.value !== null) {
178
- this.setGenericTag(tagType, tag);
179
- }
180
- }
181
- /**
182
- * Convert native tags to common tags
183
- * @returns {IAudioMetadata} Native + common tags
184
- */
185
- toCommonMetadata() {
186
- return {
187
- format: this.format,
188
- native: this.native,
189
- quality: this.quality,
190
- common: this.common
191
- };
192
- }
193
- /**
194
- * Fix some common issues with picture object
195
- * @param picture Picture
196
- */
197
- async postFixPicture(picture) {
198
- if (picture.data && picture.data.length > 0) {
199
- if (!picture.format) {
200
- const fileType = await FileType.fromBuffer(picture.data);
201
- if (fileType) {
202
- picture.format = fileType.mime;
203
- }
204
- else {
205
- return null;
206
- }
207
- }
208
- picture.format = picture.format.toLocaleLowerCase();
209
- switch (picture.format) {
210
- case 'image/jpg':
211
- picture.format = 'image/jpeg'; // ToDo: register warning
212
- }
213
- return picture;
214
- }
215
- this.addWarning(`Empty picture tag found`);
216
- return null;
217
- }
218
- /**
219
- * Convert native tag to common tags
220
- */
221
- toCommon(tagType, tagId, value) {
222
- const tag = { id: tagId, value };
223
- const genericTag = this.tagMapper.mapTag(tagType, tag, this);
224
- if (genericTag) {
225
- this.postMap(tagType, genericTag);
226
- }
227
- }
228
- /**
229
- * Set generic tag
230
- */
231
- setGenericTag(tagType, tag) {
232
- debug(`common.${tag.id} = ${tag.value}`);
233
- const prio0 = this.commonOrigin[tag.id] || 1000;
234
- const prio1 = this.originPriority[tagType];
235
- if ((0, GenericTagTypes_1.isSingleton)(tag.id)) {
236
- if (prio1 <= prio0) {
237
- this.common[tag.id] = tag.value;
238
- this.commonOrigin[tag.id] = prio1;
239
- }
240
- else {
241
- return debug(`Ignore native tag (singleton): ${tagType}.${tag.id} = ${tag.value}`);
242
- }
243
- }
244
- else {
245
- if (prio1 === prio0) {
246
- if (!(0, GenericTagTypes_1.isUnique)(tag.id) || this.common[tag.id].indexOf(tag.value) === -1) {
247
- this.common[tag.id].push(tag.value);
248
- }
249
- else {
250
- debug(`Ignore duplicate value: ${tagType}.${tag.id} = ${tag.value}`);
251
- }
252
- // no effect? this.commonOrigin[tag.id] = prio1;
253
- }
254
- else if (prio1 < prio0) {
255
- this.common[tag.id] = [tag.value];
256
- this.commonOrigin[tag.id] = prio1;
257
- }
258
- else {
259
- return debug(`Ignore native tag (list): ${tagType}.${tag.id} = ${tag.value}`);
260
- }
261
- }
262
- if (this.opts.observer) {
263
- this.opts.observer({ metadata: this, tag: { type: 'common', id: tag.id, value: tag.value } });
264
- }
265
- // ToDo: trigger metadata event
266
- }
267
- }
268
- exports.MetadataCollector = MetadataCollector;
269
- function joinArtists(artists) {
270
- if (artists.length > 2) {
271
- return artists.slice(0, artists.length - 1).join(', ') + ' & ' + artists[artists.length - 1];
272
- }
273
- return artists.join(' & ');
274
- }
275
- exports.joinArtists = joinArtists;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.joinArtists = exports.MetadataCollector = void 0;
4
+ const type_1 = require("../type");
5
+ const initDebug = require("debug");
6
+ const GenericTagTypes_1 = require("./GenericTagTypes");
7
+ const CombinedTagMapper_1 = require("./CombinedTagMapper");
8
+ const GenericTagMapper_1 = require("./GenericTagMapper");
9
+ const Util_1 = require("./Util");
10
+ const FileType = require("file-type/core");
11
+ const debug = initDebug('music-metadata:collector');
12
+ const TagPriority = ['matroska', 'APEv2', 'vorbis', 'ID3v2.4', 'ID3v2.3', 'ID3v2.2', 'exif', 'asf', 'iTunes', 'ID3v1'];
13
+ /**
14
+ * Provided to the parser to uodate the metadata result.
15
+ * Responsible for triggering async updates
16
+ */
17
+ class MetadataCollector {
18
+ constructor(opts) {
19
+ this.opts = opts;
20
+ this.format = {
21
+ tagTypes: [],
22
+ trackInfo: []
23
+ };
24
+ this.native = {};
25
+ this.common = {
26
+ track: { no: null, of: null },
27
+ disk: { no: null, of: null },
28
+ movementIndex: {}
29
+ };
30
+ this.quality = {
31
+ warnings: []
32
+ };
33
+ /**
34
+ * Keeps track of origin priority for each mapped id
35
+ */
36
+ this.commonOrigin = {};
37
+ /**
38
+ * Maps a tag type to a priority
39
+ */
40
+ this.originPriority = {};
41
+ this.tagMapper = new CombinedTagMapper_1.CombinedTagMapper();
42
+ let priority = 1;
43
+ for (const tagType of TagPriority) {
44
+ this.originPriority[tagType] = priority++;
45
+ }
46
+ this.originPriority.artificial = 500; // Filled using alternative tags
47
+ this.originPriority.id3v1 = 600; // Consider worst due to field length limit
48
+ }
49
+ /**
50
+ * @returns {boolean} true if one or more tags have been found
51
+ */
52
+ hasAny() {
53
+ return Object.keys(this.native).length > 0;
54
+ }
55
+ addStreamInfo(streamInfo) {
56
+ debug(`streamInfo: type=${type_1.TrackType[streamInfo.type]}, codec=${streamInfo.codecName}`);
57
+ this.format.trackInfo.push(streamInfo);
58
+ }
59
+ setFormat(key, value) {
60
+ debug(`format: ${key} = ${value}`);
61
+ this.format[key] = value; // as any to override readonly
62
+ if (this.opts.observer) {
63
+ this.opts.observer({ metadata: this, tag: { type: 'format', id: key, value } });
64
+ }
65
+ }
66
+ addTag(tagType, tagId, value) {
67
+ debug(`tag ${tagType}.${tagId} = ${value}`);
68
+ if (!this.native[tagType]) {
69
+ this.format.tagTypes.push(tagType);
70
+ this.native[tagType] = [];
71
+ }
72
+ this.native[tagType].push({ id: tagId, value });
73
+ this.toCommon(tagType, tagId, value);
74
+ }
75
+ addWarning(warning) {
76
+ this.quality.warnings.push({ message: warning });
77
+ }
78
+ postMap(tagType, tag) {
79
+ // Common tag (alias) found
80
+ // check if we need to do something special with common tag
81
+ // if the event has been aliased then we need to clean it before
82
+ // it is emitted to the user. e.g. genre (20) -> Electronic
83
+ switch (tag.id) {
84
+ case 'artist':
85
+ if (this.commonOrigin.artist === this.originPriority[tagType]) {
86
+ // Assume the artist field is used as artists
87
+ return this.postMap('artificial', { id: 'artists', value: tag.value });
88
+ }
89
+ if (!this.common.artists) {
90
+ // Fill artists using artist source
91
+ this.setGenericTag('artificial', { id: 'artists', value: tag.value });
92
+ }
93
+ break;
94
+ case 'artists':
95
+ if (!this.common.artist || this.commonOrigin.artist === this.originPriority.artificial) {
96
+ if (!this.common.artists || this.common.artists.indexOf(tag.value) === -1) {
97
+ // Fill artist using artists source
98
+ const artists = (this.common.artists || []).concat([tag.value]);
99
+ const value = joinArtists(artists);
100
+ const artistTag = { id: 'artist', value };
101
+ this.setGenericTag('artificial', artistTag);
102
+ }
103
+ }
104
+ break;
105
+ case 'picture':
106
+ this.postFixPicture(tag.value).then(picture => {
107
+ if (picture !== null) {
108
+ tag.value = picture;
109
+ this.setGenericTag(tagType, tag);
110
+ }
111
+ });
112
+ return;
113
+ case 'totaltracks':
114
+ this.common.track.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value);
115
+ return;
116
+ case 'totaldiscs':
117
+ this.common.disk.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value);
118
+ return;
119
+ case 'movementTotal':
120
+ this.common.movementIndex.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value);
121
+ return;
122
+ case 'track':
123
+ case 'disk':
124
+ case 'movementIndex':
125
+ const of = this.common[tag.id].of; // store of value, maybe maybe overwritten
126
+ this.common[tag.id] = GenericTagMapper_1.CommonTagMapper.normalizeTrack(tag.value);
127
+ this.common[tag.id].of = of != null ? of : this.common[tag.id].of;
128
+ return;
129
+ case 'bpm':
130
+ case 'year':
131
+ case 'originalyear':
132
+ tag.value = parseInt(tag.value, 10);
133
+ break;
134
+ case 'date':
135
+ // ToDo: be more strict on 'YYYY...'
136
+ const year = parseInt(tag.value.substr(0, 4), 10);
137
+ if (!isNaN(year)) {
138
+ this.common.year = year;
139
+ }
140
+ break;
141
+ case 'discogs_label_id':
142
+ case 'discogs_release_id':
143
+ case 'discogs_master_release_id':
144
+ case 'discogs_artist_id':
145
+ case 'discogs_votes':
146
+ tag.value = typeof tag.value === 'string' ? parseInt(tag.value, 10) : tag.value;
147
+ break;
148
+ case 'replaygain_track_gain':
149
+ case 'replaygain_track_peak':
150
+ case 'replaygain_album_gain':
151
+ case 'replaygain_album_peak':
152
+ tag.value = (0, Util_1.toRatio)(tag.value);
153
+ break;
154
+ case 'replaygain_track_minmax':
155
+ tag.value = tag.value.split(',').map(v => parseInt(v, 10));
156
+ break;
157
+ case 'replaygain_undo':
158
+ const minMix = tag.value.split(',').map(v => parseInt(v, 10));
159
+ tag.value = {
160
+ leftChannel: minMix[0],
161
+ rightChannel: minMix[1]
162
+ };
163
+ break;
164
+ case 'gapless': // iTunes gap-less flag
165
+ case 'compilation':
166
+ case 'podcast':
167
+ case 'showMovement':
168
+ tag.value = tag.value === '1' || tag.value === 1; // boolean
169
+ break;
170
+ case 'isrc': // Only keep unique values
171
+ if (this.common[tag.id] && this.common[tag.id].indexOf(tag.value) !== -1)
172
+ return;
173
+ break;
174
+ default:
175
+ // nothing to do
176
+ }
177
+ if (tag.value !== null) {
178
+ this.setGenericTag(tagType, tag);
179
+ }
180
+ }
181
+ /**
182
+ * Convert native tags to common tags
183
+ * @returns {IAudioMetadata} Native + common tags
184
+ */
185
+ toCommonMetadata() {
186
+ return {
187
+ format: this.format,
188
+ native: this.native,
189
+ quality: this.quality,
190
+ common: this.common
191
+ };
192
+ }
193
+ /**
194
+ * Fix some common issues with picture object
195
+ * @param picture Picture
196
+ */
197
+ async postFixPicture(picture) {
198
+ if (picture.data && picture.data.length > 0) {
199
+ if (!picture.format) {
200
+ const fileType = await FileType.fromBuffer(picture.data);
201
+ if (fileType) {
202
+ picture.format = fileType.mime;
203
+ }
204
+ else {
205
+ return null;
206
+ }
207
+ }
208
+ picture.format = picture.format.toLocaleLowerCase();
209
+ switch (picture.format) {
210
+ case 'image/jpg':
211
+ picture.format = 'image/jpeg'; // ToDo: register warning
212
+ }
213
+ return picture;
214
+ }
215
+ this.addWarning(`Empty picture tag found`);
216
+ return null;
217
+ }
218
+ /**
219
+ * Convert native tag to common tags
220
+ */
221
+ toCommon(tagType, tagId, value) {
222
+ const tag = { id: tagId, value };
223
+ const genericTag = this.tagMapper.mapTag(tagType, tag, this);
224
+ if (genericTag) {
225
+ this.postMap(tagType, genericTag);
226
+ }
227
+ }
228
+ /**
229
+ * Set generic tag
230
+ */
231
+ setGenericTag(tagType, tag) {
232
+ debug(`common.${tag.id} = ${tag.value}`);
233
+ const prio0 = this.commonOrigin[tag.id] || 1000;
234
+ const prio1 = this.originPriority[tagType];
235
+ if ((0, GenericTagTypes_1.isSingleton)(tag.id)) {
236
+ if (prio1 <= prio0) {
237
+ this.common[tag.id] = tag.value;
238
+ this.commonOrigin[tag.id] = prio1;
239
+ }
240
+ else {
241
+ return debug(`Ignore native tag (singleton): ${tagType}.${tag.id} = ${tag.value}`);
242
+ }
243
+ }
244
+ else {
245
+ if (prio1 === prio0) {
246
+ if (!(0, GenericTagTypes_1.isUnique)(tag.id) || this.common[tag.id].indexOf(tag.value) === -1) {
247
+ this.common[tag.id].push(tag.value);
248
+ }
249
+ else {
250
+ debug(`Ignore duplicate value: ${tagType}.${tag.id} = ${tag.value}`);
251
+ }
252
+ // no effect? this.commonOrigin[tag.id] = prio1;
253
+ }
254
+ else if (prio1 < prio0) {
255
+ this.common[tag.id] = [tag.value];
256
+ this.commonOrigin[tag.id] = prio1;
257
+ }
258
+ else {
259
+ return debug(`Ignore native tag (list): ${tagType}.${tag.id} = ${tag.value}`);
260
+ }
261
+ }
262
+ if (this.opts.observer) {
263
+ this.opts.observer({ metadata: this, tag: { type: 'common', id: tag.id, value: tag.value } });
264
+ }
265
+ // ToDo: trigger metadata event
266
+ }
267
+ }
268
+ exports.MetadataCollector = MetadataCollector;
269
+ function joinArtists(artists) {
270
+ if (artists.length > 2) {
271
+ return artists.slice(0, artists.length - 1).join(', ') + ' & ' + artists[artists.length - 1];
272
+ }
273
+ return artists.join(' & ');
274
+ }
275
+ exports.joinArtists = joinArtists;
276
276
  //# sourceMappingURL=MetadataCollector.js.map
@@ -1,20 +1,22 @@
1
- /// <reference types="node" />
2
- import { IRandomReader } from '../type';
3
- /**
4
- * Provides abstract file access via the IRandomRead interface
5
- */
6
- export declare class RandomFileReader implements IRandomReader {
7
- fileSize: number;
8
- private readonly fd;
9
- constructor(filePath: string, fileSize: number);
10
- /**
11
- * Read from a given position of an abstracted file or buffer.
12
- * @param buffer {Buffer} is the buffer that the data will be written to.
13
- * @param offset {number} is the offset in the buffer to start writing at.
14
- * @param length {number}is an integer specifying the number of bytes to read.
15
- * @param position {number} is an argument specifying where to begin reading from in the file.
16
- * @return {Promise<number>} bytes read
17
- */
18
- randomRead(buffer: Buffer, offset: number, length: number, position: number): Promise<number>;
19
- close(): void;
20
- }
1
+ /// <reference types="node" />
2
+ import { IRandomReader } from '../type';
3
+ /**
4
+ * Provides abstract file access via the IRandomRead interface
5
+ */
6
+ export declare class RandomFileReader implements IRandomReader {
7
+ private readonly fileHandle;
8
+ filePath: string;
9
+ fileSize: number;
10
+ private constructor();
11
+ /**
12
+ * Read from a given position of an abstracted file or buffer.
13
+ * @param buffer {Buffer} is the buffer that the data will be written to.
14
+ * @param offset {number} is the offset in the buffer to start writing at.
15
+ * @param length {number}is an integer specifying the number of bytes to read.
16
+ * @param position {number} is an argument specifying where to begin reading from in the file.
17
+ * @return {Promise<number>} bytes read
18
+ */
19
+ randomRead(buffer: Buffer, offset: number, length: number, position: number): Promise<number>;
20
+ close(): Promise<void>;
21
+ static init(filePath: string, fileSize: number): Promise<RandomFileReader>;
22
+ }