music-metadata 7.13.4 → 7.14.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.
package/lib/mp4/MP4Parser.js
CHANGED
|
@@ -178,7 +178,7 @@ class MP4Parser extends BasicParser_1.BasicParser {
|
|
|
178
178
|
this.getTrackDescription().sampleToChunkTable = stsc.entries;
|
|
179
179
|
},
|
|
180
180
|
/**
|
|
181
|
-
* time
|
|
181
|
+
* time-to-sample table
|
|
182
182
|
*/
|
|
183
183
|
stts: async (len) => {
|
|
184
184
|
const stts = await this.tokenizer.readToken(new AtomToken.SttsAtom(len));
|
|
@@ -275,13 +275,22 @@ class MP4Parser extends BasicParser_1.BasicParser {
|
|
|
275
275
|
});
|
|
276
276
|
if (audioTracks.length >= 1) {
|
|
277
277
|
const audioTrack = audioTracks[0];
|
|
278
|
-
|
|
279
|
-
|
|
278
|
+
if (audioTrack.timeScale > 0) {
|
|
279
|
+
const duration = audioTrack.duration / audioTrack.timeScale; // calculate duration in seconds
|
|
280
|
+
this.metadata.setFormat('duration', duration);
|
|
281
|
+
}
|
|
280
282
|
const ssd = audioTrack.soundSampleDescription[0];
|
|
281
283
|
if (ssd.description) {
|
|
282
284
|
this.metadata.setFormat('sampleRate', ssd.description.sampleRate);
|
|
283
285
|
this.metadata.setFormat('bitsPerSample', ssd.description.sampleSize);
|
|
284
286
|
this.metadata.setFormat('numberOfChannels', ssd.description.numAudioChannels);
|
|
287
|
+
if (audioTrack.timeScale === 0 && audioTrack.timeToSampleTable.length > 0) {
|
|
288
|
+
const totalSampleSize = audioTrack.timeToSampleTable
|
|
289
|
+
.map(ttstEntry => ttstEntry.count * ttstEntry.duration)
|
|
290
|
+
.reduce((total, sampleSize) => total + sampleSize);
|
|
291
|
+
const duration = totalSampleSize / ssd.description.sampleRate;
|
|
292
|
+
this.metadata.setFormat('duration', duration);
|
|
293
|
+
}
|
|
285
294
|
}
|
|
286
295
|
const encoderInfo = encoderDict[ssd.dataFormat];
|
|
287
296
|
if (encoderInfo) {
|
|
@@ -335,14 +344,11 @@ class MP4Parser extends BasicParser_1.BasicParser {
|
|
|
335
344
|
case 'data': // value atom
|
|
336
345
|
return this.parseValueAtom(tagKey, child);
|
|
337
346
|
case 'name': // name atom (optional)
|
|
347
|
+
case 'mean':
|
|
348
|
+
case 'rate':
|
|
338
349
|
const name = await this.tokenizer.readToken(new AtomToken.NameAtom(payLoadLength));
|
|
339
350
|
tagKey += ':' + name.name;
|
|
340
351
|
break;
|
|
341
|
-
case 'mean': // name atom (optional)
|
|
342
|
-
const mean = await this.tokenizer.readToken(new AtomToken.NameAtom(payLoadLength));
|
|
343
|
-
// console.log(" %s[%s] = %s", tagKey, header.name, mean.name);
|
|
344
|
-
tagKey += ':' + mean.name;
|
|
345
|
-
break;
|
|
346
352
|
default:
|
|
347
353
|
const dataAtom = await this.tokenizer.readToken(new Token.BufferType(payLoadLength));
|
|
348
354
|
this.addWarning('Unsupported meta-item: ' + tagKey + '[' + child.header.name + '] => value=' + dataAtom.toString('hex') + ' ascii=' + dataAtom.toString('ascii'));
|
|
@@ -372,9 +378,12 @@ class MP4Parser extends BasicParser_1.BasicParser {
|
|
|
372
378
|
// console.log(" %s[data] = %s", tagKey, genreStr);
|
|
373
379
|
this.addTag(tagKey, genreStr);
|
|
374
380
|
break;
|
|
381
|
+
case 'rate':
|
|
382
|
+
const rate = dataAtom.value.toString('ascii');
|
|
383
|
+
this.addTag(tagKey, rate);
|
|
384
|
+
break;
|
|
375
385
|
default:
|
|
376
|
-
|
|
377
|
-
// header.name, header.length, dataAtom.type.set, dataAtom.type.type, dataAtom.locale, dataAtom.value.toString('hex'), dataAtom.value.toString('ascii'));
|
|
386
|
+
debug('unknown proprietary value type for: ' + metaAtom.atomPath);
|
|
378
387
|
}
|
|
379
388
|
break;
|
|
380
389
|
case 1: // UTF-8: Without any count or NULL terminator
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { CaseInsensitiveTagMap } from '../common/CaseInsensitiveTagMap';
|
|
2
|
+
import { ITag } from "../type";
|
|
3
|
+
import { INativeMetadataCollector } from "../common/MetadataCollector";
|
|
2
4
|
export declare const tagType = "iTunes";
|
|
3
5
|
export declare class MP4TagMapper extends CaseInsensitiveTagMap {
|
|
4
6
|
constructor();
|
|
7
|
+
protected postMap(tag: ITag, warnings: INativeMetadataCollector): void;
|
|
5
8
|
}
|
package/lib/mp4/MP4TagMapper.js
CHANGED
|
@@ -104,13 +104,24 @@ const mp4TagMap = {
|
|
|
104
104
|
hdvd: 'hdVideo',
|
|
105
105
|
keyw: 'keywords',
|
|
106
106
|
shwm: 'showMovement',
|
|
107
|
-
stik: 'stik'
|
|
107
|
+
stik: 'stik',
|
|
108
|
+
rate: 'rating'
|
|
108
109
|
};
|
|
109
110
|
exports.tagType = 'iTunes';
|
|
110
111
|
class MP4TagMapper extends CaseInsensitiveTagMap_1.CaseInsensitiveTagMap {
|
|
111
112
|
constructor() {
|
|
112
113
|
super([exports.tagType], mp4TagMap);
|
|
113
114
|
}
|
|
115
|
+
postMap(tag, warnings) {
|
|
116
|
+
switch (tag.id) {
|
|
117
|
+
case 'rate':
|
|
118
|
+
tag.value = {
|
|
119
|
+
source: undefined,
|
|
120
|
+
rating: parseFloat(tag.value) / 100
|
|
121
|
+
};
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
114
125
|
}
|
|
115
126
|
exports.MP4TagMapper = MP4TagMapper;
|
|
116
127
|
//# sourceMappingURL=MP4TagMapper.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CommonTagMapper } from '../../common/GenericTagMapper';
|
|
2
2
|
import { IRating, ITag } from '../../type';
|
|
3
3
|
export declare class VorbisTagMapper extends CommonTagMapper {
|
|
4
|
-
static toRating(email: string, rating: string): IRating;
|
|
4
|
+
static toRating(email: string, rating: string, maxScore: number): IRating;
|
|
5
5
|
constructor();
|
|
6
6
|
protected postMap(tag: ITag): void;
|
|
7
7
|
}
|
|
@@ -112,19 +112,23 @@ const vorbisTagMap = {
|
|
|
112
112
|
REPLAYGAIN_UNDO: 'replaygain_undo'
|
|
113
113
|
};
|
|
114
114
|
class VorbisTagMapper extends GenericTagMapper_1.CommonTagMapper {
|
|
115
|
-
static toRating(email, rating) {
|
|
115
|
+
static toRating(email, rating, maxScore) {
|
|
116
116
|
return {
|
|
117
117
|
source: email ? email.toLowerCase() : email,
|
|
118
|
-
rating: parseFloat(rating) * GenericTagMapper_1.CommonTagMapper.maxRatingScore
|
|
118
|
+
rating: (parseFloat(rating) / maxScore) * GenericTagMapper_1.CommonTagMapper.maxRatingScore
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
121
|
constructor() {
|
|
122
122
|
super(['vorbis'], vorbisTagMap);
|
|
123
123
|
}
|
|
124
124
|
postMap(tag) {
|
|
125
|
-
if (tag.id
|
|
125
|
+
if (tag.id === 'RATING') {
|
|
126
|
+
// The way Winamp 5.666 assigns rating
|
|
127
|
+
tag.value = VorbisTagMapper.toRating(undefined, tag.value, 100);
|
|
128
|
+
}
|
|
129
|
+
else if (tag.id.indexOf('RATING:') === 0) {
|
|
126
130
|
const keys = tag.id.split(':');
|
|
127
|
-
tag.value = VorbisTagMapper.toRating(keys[1], tag.value);
|
|
131
|
+
tag.value = VorbisTagMapper.toRating(keys[1], tag.value, 1);
|
|
128
132
|
tag.id = keys[0];
|
|
129
133
|
}
|
|
130
134
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "music-metadata",
|
|
3
3
|
"description": "Music metadata parser for Node.js, supporting virtual any audio and tag format.",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.14.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Borewit",
|
|
7
7
|
"url": "https://github.com/Borewit"
|
|
@@ -92,30 +92,30 @@
|
|
|
92
92
|
"token-types": "^4.2.1"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
|
-
"@types/chai": "^4.3.
|
|
96
|
-
"@types/chai-as-promised": "^7.1.
|
|
97
|
-
"@types/debug": "^4.1.
|
|
95
|
+
"@types/chai": "^4.3.9",
|
|
96
|
+
"@types/chai-as-promised": "^7.1.7",
|
|
97
|
+
"@types/debug": "^4.1.10",
|
|
98
98
|
"@types/file-type": "^10.9.1",
|
|
99
99
|
"@types/mocha": "^9.1.1",
|
|
100
|
-
"@types/node": "^
|
|
101
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
102
|
-
"@typescript-eslint/parser": "^5.
|
|
103
|
-
"chai": "^4.3.
|
|
100
|
+
"@types/node": "^20.8.9",
|
|
101
|
+
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
102
|
+
"@typescript-eslint/parser": "^5.62.0",
|
|
103
|
+
"chai": "^4.3.10",
|
|
104
104
|
"chai-as-promised": "^7.1.1",
|
|
105
|
-
"del-cli": "5.
|
|
106
|
-
"eslint": "^8.
|
|
107
|
-
"eslint-config-prettier": "^
|
|
108
|
-
"eslint-import-resolver-typescript": "^3.
|
|
109
|
-
"eslint-plugin-import": "^2.
|
|
110
|
-
"eslint-plugin-jsdoc": "^
|
|
105
|
+
"del-cli": "5.1.0",
|
|
106
|
+
"eslint": "^8.53.0",
|
|
107
|
+
"eslint-config-prettier": "^9.0.0",
|
|
108
|
+
"eslint-import-resolver-typescript": "^3.6.1",
|
|
109
|
+
"eslint-plugin-import": "^2.29.0",
|
|
110
|
+
"eslint-plugin-jsdoc": "^46.8.2",
|
|
111
111
|
"eslint-plugin-node": "^11.1.0",
|
|
112
|
-
"eslint-plugin-unicorn": "^
|
|
112
|
+
"eslint-plugin-unicorn": "^49.0.0",
|
|
113
113
|
"mime": "^3.0.0",
|
|
114
114
|
"mocha": "^9.2.2",
|
|
115
115
|
"npm-run-all": "^4.1.5",
|
|
116
116
|
"nyc": "^15.1.0",
|
|
117
|
-
"remark-cli": "^
|
|
118
|
-
"remark-preset-lint-recommended": "^6.1.
|
|
117
|
+
"remark-cli": "^12.0.0",
|
|
118
|
+
"remark-preset-lint-recommended": "^6.1.3",
|
|
119
119
|
"source-map-support": "^0.5.21",
|
|
120
120
|
"ts-node": "^10.9.1",
|
|
121
121
|
"typescript": "^5.0.2"
|