music-metadata 7.11.1 → 7.11.5

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 (152) hide show
  1. package/README.md +432 -432
  2. package/lib/ParserFactory.d.ts +49 -49
  3. package/lib/ParserFactory.js +251 -251
  4. package/lib/aiff/AiffParser.d.ts +15 -15
  5. package/lib/aiff/AiffParser.js +85 -85
  6. package/lib/aiff/AiffToken.d.ts +22 -22
  7. package/lib/aiff/AiffToken.js +43 -43
  8. package/lib/apev2/APEv2Parser.d.ts +30 -30
  9. package/lib/apev2/APEv2Parser.js +162 -162
  10. package/lib/apev2/APEv2TagMapper.d.ts +4 -4
  11. package/lib/apev2/APEv2TagMapper.js +87 -86
  12. package/lib/apev2/APEv2Token.d.ts +100 -100
  13. package/lib/apev2/APEv2Token.js +127 -126
  14. package/lib/asf/AsfObject.d.ts +319 -319
  15. package/lib/asf/AsfObject.js +384 -384
  16. package/lib/asf/AsfParser.d.ts +17 -17
  17. package/lib/asf/AsfParser.js +135 -135
  18. package/lib/asf/AsfTagMapper.d.ts +7 -7
  19. package/lib/asf/AsfTagMapper.js +96 -95
  20. package/lib/asf/AsfUtil.d.ts +13 -13
  21. package/lib/asf/AsfUtil.js +40 -40
  22. package/lib/asf/GUID.d.ts +86 -86
  23. package/lib/asf/GUID.js +123 -123
  24. package/lib/common/BasicParser.d.ts +17 -17
  25. package/lib/common/BasicParser.js +18 -18
  26. package/lib/common/CaseInsensitiveTagMap.d.ts +10 -10
  27. package/lib/common/CaseInsensitiveTagMap.js +22 -21
  28. package/lib/common/CombinedTagMapper.d.ts +19 -19
  29. package/lib/common/CombinedTagMapper.js +52 -51
  30. package/lib/common/FourCC.d.ts +6 -6
  31. package/lib/common/FourCC.js +29 -28
  32. package/lib/common/GenericTagMapper.d.ts +51 -51
  33. package/lib/common/GenericTagMapper.js +56 -55
  34. package/lib/common/GenericTagTypes.d.ts +33 -33
  35. package/lib/common/GenericTagTypes.js +132 -131
  36. package/lib/common/MetadataCollector.d.ts +76 -76
  37. package/lib/common/MetadataCollector.js +276 -274
  38. package/lib/common/RandomFileReader.d.ts +20 -20
  39. package/lib/common/RandomFileReader.js +37 -37
  40. package/lib/common/RandomUint8ArrayReader.d.ts +18 -18
  41. package/lib/common/RandomUint8ArrayReader.js +25 -25
  42. package/lib/common/Util.d.ts +57 -57
  43. package/lib/common/Util.js +170 -169
  44. package/lib/core.d.ts +48 -48
  45. package/lib/core.js +90 -90
  46. package/lib/dsdiff/DsdiffParser.d.ts +14 -14
  47. package/lib/dsdiff/DsdiffParser.js +143 -143
  48. package/lib/dsdiff/DsdiffToken.d.ts +9 -9
  49. package/lib/dsdiff/DsdiffToken.js +21 -21
  50. package/lib/dsf/DsfChunk.d.ts +86 -86
  51. package/lib/dsf/DsfChunk.js +54 -54
  52. package/lib/dsf/DsfParser.d.ts +9 -9
  53. package/lib/dsf/DsfParser.js +56 -56
  54. package/lib/flac/FlacParser.d.ts +28 -28
  55. package/lib/flac/FlacParser.js +175 -175
  56. package/lib/id3v1/ID3v1Parser.d.ts +13 -13
  57. package/lib/id3v1/ID3v1Parser.js +134 -134
  58. package/lib/id3v1/ID3v1TagMap.d.ts +4 -4
  59. package/lib/id3v1/ID3v1TagMap.js +23 -22
  60. package/lib/id3v2/AbstractID3Parser.d.ts +17 -17
  61. package/lib/id3v2/AbstractID3Parser.js +60 -60
  62. package/lib/id3v2/FrameParser.d.ts +32 -32
  63. package/lib/id3v2/FrameParser.js +323 -323
  64. package/lib/id3v2/ID3v22TagMapper.d.ts +9 -9
  65. package/lib/id3v2/ID3v22TagMapper.js +56 -54
  66. package/lib/id3v2/ID3v24TagMapper.d.ts +14 -14
  67. package/lib/id3v2/ID3v24TagMapper.js +194 -193
  68. package/lib/id3v2/ID3v2Parser.d.ts +29 -29
  69. package/lib/id3v2/ID3v2Parser.js +194 -194
  70. package/lib/id3v2/ID3v2Token.d.ts +73 -73
  71. package/lib/id3v2/ID3v2Token.js +106 -106
  72. package/lib/iff/index.d.ts +33 -33
  73. package/lib/iff/index.js +19 -19
  74. package/lib/index.d.ts +34 -34
  75. package/lib/index.js +64 -64
  76. package/lib/lyrics3/Lyrics3.d.ts +3 -3
  77. package/lib/lyrics3/Lyrics3.js +17 -17
  78. package/lib/matroska/MatroskaDtd.d.ts +8 -8
  79. package/lib/matroska/MatroskaDtd.js +279 -279
  80. package/lib/matroska/MatroskaParser.d.ts +37 -37
  81. package/lib/matroska/MatroskaParser.js +235 -234
  82. package/lib/matroska/MatroskaTagMapper.d.ts +4 -4
  83. package/lib/matroska/MatroskaTagMapper.js +36 -35
  84. package/lib/matroska/types.d.ts +175 -175
  85. package/lib/matroska/types.js +32 -32
  86. package/lib/mp4/Atom.d.ts +16 -16
  87. package/lib/mp4/Atom.js +70 -70
  88. package/lib/mp4/AtomToken.d.ts +395 -395
  89. package/lib/mp4/AtomToken.js +406 -406
  90. package/lib/mp4/MP4Parser.d.ts +30 -31
  91. package/lib/mp4/MP4Parser.js +511 -515
  92. package/lib/mp4/MP4TagMapper.d.ts +5 -5
  93. package/lib/mp4/MP4TagMapper.js +116 -115
  94. package/lib/mpeg/ExtendedLameHeader.d.ts +27 -27
  95. package/lib/mpeg/ExtendedLameHeader.js +31 -31
  96. package/lib/mpeg/MpegParser.d.ts +49 -49
  97. package/lib/mpeg/MpegParser.js +529 -529
  98. package/lib/mpeg/ReplayGainDataFormat.d.ts +55 -55
  99. package/lib/mpeg/ReplayGainDataFormat.js +69 -69
  100. package/lib/mpeg/XingTag.d.ts +45 -45
  101. package/lib/mpeg/XingTag.js +69 -69
  102. package/lib/musepack/index.d.ts +5 -5
  103. package/lib/musepack/index.js +32 -32
  104. package/lib/musepack/sv7/BitReader.d.ts +13 -13
  105. package/lib/musepack/sv7/BitReader.js +54 -54
  106. package/lib/musepack/sv7/MpcSv7Parser.d.ts +8 -8
  107. package/lib/musepack/sv7/MpcSv7Parser.js +46 -46
  108. package/lib/musepack/sv7/StreamVersion7.d.ts +28 -28
  109. package/lib/musepack/sv7/StreamVersion7.js +41 -41
  110. package/lib/musepack/sv8/MpcSv8Parser.d.ts +6 -6
  111. package/lib/musepack/sv8/MpcSv8Parser.js +55 -55
  112. package/lib/musepack/sv8/StreamVersion8.d.ts +40 -40
  113. package/lib/musepack/sv8/StreamVersion8.js +80 -80
  114. package/lib/ogg/Ogg.d.ts +72 -72
  115. package/lib/ogg/Ogg.js +2 -2
  116. package/lib/ogg/OggParser.d.ts +23 -23
  117. package/lib/ogg/OggParser.js +126 -126
  118. package/lib/ogg/opus/Opus.d.ts +48 -48
  119. package/lib/ogg/opus/Opus.js +28 -28
  120. package/lib/ogg/opus/OpusParser.d.ts +25 -25
  121. package/lib/ogg/opus/OpusParser.js +56 -56
  122. package/lib/ogg/speex/Speex.d.ts +36 -36
  123. package/lib/ogg/speex/Speex.js +31 -31
  124. package/lib/ogg/speex/SpeexParser.d.ts +22 -22
  125. package/lib/ogg/speex/SpeexParser.js +35 -35
  126. package/lib/ogg/theora/Theora.d.ts +20 -20
  127. package/lib/ogg/theora/Theora.js +23 -23
  128. package/lib/ogg/theora/TheoraParser.d.ts +28 -28
  129. package/lib/ogg/theora/TheoraParser.js +44 -44
  130. package/lib/ogg/vorbis/Vorbis.d.ts +79 -79
  131. package/lib/ogg/vorbis/Vorbis.js +78 -78
  132. package/lib/ogg/vorbis/VorbisDecoder.d.ts +12 -12
  133. package/lib/ogg/vorbis/VorbisDecoder.js +32 -32
  134. package/lib/ogg/vorbis/VorbisParser.d.ts +36 -36
  135. package/lib/ogg/vorbis/VorbisParser.js +128 -128
  136. package/lib/ogg/vorbis/VorbisTagMapper.d.ts +7 -7
  137. package/lib/ogg/vorbis/VorbisTagMapper.js +133 -132
  138. package/lib/riff/RiffChunk.d.ts +16 -16
  139. package/lib/riff/RiffChunk.js +32 -32
  140. package/lib/riff/RiffInfoTagMap.d.ts +10 -10
  141. package/lib/riff/RiffInfoTagMap.js +38 -37
  142. package/lib/type.d.ts +599 -599
  143. package/lib/type.js +14 -13
  144. package/lib/wav/WaveChunk.d.ts +64 -64
  145. package/lib/wav/WaveChunk.js +65 -65
  146. package/lib/wav/WaveParser.d.ts +24 -24
  147. package/lib/wav/WaveParser.js +144 -144
  148. package/lib/wavpack/WavPackParser.d.ts +14 -14
  149. package/lib/wavpack/WavPackParser.js +105 -105
  150. package/lib/wavpack/WavPackToken.d.ts +64 -64
  151. package/lib/wavpack/WavPackToken.js +76 -76
  152. package/package.json +142 -142
@@ -1,274 +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 'year':
130
- case 'originalyear':
131
- tag.value = parseInt(tag.value, 10);
132
- break;
133
- case 'date':
134
- // ToDo: be more strict on 'YYYY...'
135
- const year = parseInt(tag.value.substr(0, 4), 10);
136
- if (!isNaN(year)) {
137
- this.common.year = year;
138
- }
139
- break;
140
- case 'discogs_label_id':
141
- case 'discogs_release_id':
142
- case 'discogs_master_release_id':
143
- case 'discogs_artist_id':
144
- case 'discogs_votes':
145
- tag.value = typeof tag.value === 'string' ? parseInt(tag.value, 10) : tag.value;
146
- break;
147
- case 'replaygain_track_gain':
148
- case 'replaygain_track_peak':
149
- case 'replaygain_album_gain':
150
- case 'replaygain_album_peak':
151
- tag.value = Util_1.toRatio(tag.value);
152
- break;
153
- case 'replaygain_track_minmax':
154
- tag.value = tag.value.split(',').map(v => parseInt(v, 10));
155
- break;
156
- case 'replaygain_undo':
157
- const minMix = tag.value.split(',').map(v => parseInt(v, 10));
158
- tag.value = {
159
- leftChannel: minMix[0],
160
- rightChannel: minMix[1]
161
- };
162
- break;
163
- case 'gapless': // iTunes gap-less flag
164
- case 'compilation':
165
- case 'podcast':
166
- case 'showMovement':
167
- tag.value = tag.value === '1' || tag.value === 1; // boolean
168
- break;
169
- case 'isrc': // Only keep unique values
170
- if (this.common[tag.id] && this.common[tag.id].indexOf(tag.value) !== -1)
171
- return;
172
- break;
173
- default:
174
- // nothing to do
175
- }
176
- if (tag.value !== null) {
177
- this.setGenericTag(tagType, tag);
178
- }
179
- }
180
- /**
181
- * Convert native tags to common tags
182
- * @returns {IAudioMetadata} Native + common tags
183
- */
184
- toCommonMetadata() {
185
- return {
186
- format: this.format,
187
- native: this.native,
188
- quality: this.quality,
189
- common: this.common
190
- };
191
- }
192
- /**
193
- * Fix some common issues with picture object
194
- * @param pictureType
195
- */
196
- async postFixPicture(picture) {
197
- if (picture.data && picture.data.length > 0) {
198
- if (!picture.format) {
199
- const fileType = await FileType.fromBuffer(picture.data);
200
- if (fileType) {
201
- picture.format = fileType.mime;
202
- }
203
- else {
204
- return null;
205
- }
206
- }
207
- picture.format = picture.format.toLocaleLowerCase();
208
- switch (picture.format) {
209
- case 'image/jpg':
210
- picture.format = 'image/jpeg'; // ToDo: register warning
211
- }
212
- return picture;
213
- }
214
- this.addWarning(`Empty picture tag found`);
215
- return null;
216
- }
217
- /**
218
- * Convert native tag to common tags
219
- */
220
- toCommon(tagType, tagId, value) {
221
- const tag = { id: tagId, value };
222
- const genericTag = this.tagMapper.mapTag(tagType, tag, this);
223
- if (genericTag) {
224
- this.postMap(tagType, genericTag);
225
- }
226
- }
227
- /**
228
- * Set generic tag
229
- */
230
- setGenericTag(tagType, tag) {
231
- debug(`common.${tag.id} = ${tag.value}`);
232
- const prio0 = this.commonOrigin[tag.id] || 1000;
233
- const prio1 = this.originPriority[tagType];
234
- if (GenericTagTypes_1.isSingleton(tag.id)) {
235
- if (prio1 <= prio0) {
236
- this.common[tag.id] = tag.value;
237
- this.commonOrigin[tag.id] = prio1;
238
- }
239
- else {
240
- return debug(`Ignore native tag (singleton): ${tagType}.${tag.id} = ${tag.value}`);
241
- }
242
- }
243
- else {
244
- if (prio1 === prio0) {
245
- if (!GenericTagTypes_1.isUnique(tag.id) || this.common[tag.id].indexOf(tag.value) === -1) {
246
- this.common[tag.id].push(tag.value);
247
- }
248
- else {
249
- debug(`Ignore duplicate value: ${tagType}.${tag.id} = ${tag.value}`);
250
- }
251
- // no effect? this.commonOrigin[tag.id] = prio1;
252
- }
253
- else if (prio1 < prio0) {
254
- this.common[tag.id] = [tag.value];
255
- this.commonOrigin[tag.id] = prio1;
256
- }
257
- else {
258
- return debug(`Ignore native tag (list): ${tagType}.${tag.id} = ${tag.value}`);
259
- }
260
- }
261
- if (this.opts.observer) {
262
- this.opts.observer({ metadata: this, tag: { type: 'common', id: tag.id, value: tag.value } });
263
- }
264
- // ToDo: trigger metadata event
265
- }
266
- }
267
- exports.MetadataCollector = MetadataCollector;
268
- function joinArtists(artists) {
269
- if (artists.length > 2) {
270
- return artists.slice(0, artists.length - 1).join(', ') + ' & ' + artists[artists.length - 1];
271
- }
272
- return artists.join(' & ');
273
- }
274
- 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 _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;
276
+ //# sourceMappingURL=MetadataCollector.js.map
@@ -1,20 +1,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
- 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
+ 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
+ }