music-metadata 9.0.3 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/common/GenericTagMapper.d.ts +1 -1
- package/lib/common/MetadataCollector.js +8 -0
- package/lib/core.d.ts +1 -0
- package/lib/core.js +1 -0
- package/lib/id3v2/FrameParser.d.ts +5 -1
- package/lib/id3v2/FrameParser.js +46 -20
- package/lib/id3v2/ID3v22TagMapper.js +0 -6
- package/lib/id3v2/ID3v24TagMapper.js +0 -7
- package/lib/id3v2/ID3v2Parser.d.ts +1 -0
- package/lib/id3v2/ID3v2Parser.js +11 -16
- package/lib/id3v2/ID3v2Token.d.ts +39 -0
- package/lib/id3v2/ID3v2Token.js +47 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -0
- package/lib/type.d.ts +26 -3
- package/lib/type.js +1 -0
- package/package.json +9 -5
|
@@ -3,7 +3,7 @@ import { ITag } from '../type.js';
|
|
|
3
3
|
import { INativeMetadataCollector, IWarningCollector } from './MetadataCollector.js';
|
|
4
4
|
export interface IGenericTagMapper {
|
|
5
5
|
/**
|
|
6
|
-
* Which tagType
|
|
6
|
+
* Which tagType is able to map to the generic mapping format
|
|
7
7
|
*/
|
|
8
8
|
tagTypes: generic.TagType[];
|
|
9
9
|
/**
|
|
@@ -167,6 +167,14 @@ export class MetadataCollector {
|
|
|
167
167
|
if (this.common[tag.id] && this.common[tag.id].indexOf(tag.value) !== -1)
|
|
168
168
|
return;
|
|
169
169
|
break;
|
|
170
|
+
case 'comment':
|
|
171
|
+
if (typeof tag.value === 'string') {
|
|
172
|
+
tag.value = { text: tag.value };
|
|
173
|
+
}
|
|
174
|
+
if (tag.value.descriptor === 'iTunPGAP') {
|
|
175
|
+
this.setGenericTag(tagType, { id: 'gapless', value: tag.value.text === '1' });
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
170
178
|
default:
|
|
171
179
|
// nothing to do
|
|
172
180
|
}
|
package/lib/core.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import * as strtok3 from 'strtok3';
|
|
|
5
5
|
import type { IAudioMetadata, INativeTagDict, IOptions, IPicture, IPrivateOptions, IRandomReader, ITag } from './type.js';
|
|
6
6
|
import type { ReadableStream as NodeReadableStream } from 'node:stream/web';
|
|
7
7
|
export { IFileInfo } from 'strtok3';
|
|
8
|
+
export { IAudioMetadata, IOptions, ITag, INativeTagDict, ICommonTagsResult, IFormat, IPicture, IRatio, IChapter, ILyricsTag, LyricsContentType, TimestampFormat } from './type.js';
|
|
8
9
|
export type AnyWebStream<G> = NodeReadableStream<G> | ReadableStream<G>;
|
|
9
10
|
/**
|
|
10
11
|
* Parse Web API File
|
package/lib/core.js
CHANGED
|
@@ -7,6 +7,7 @@ import { RandomUint8ArrayReader } from './common/RandomUint8ArrayReader.js';
|
|
|
7
7
|
import { APEv2Parser } from './apev2/APEv2Parser.js';
|
|
8
8
|
import { hasID3v1Header } from './id3v1/ID3v1Parser.js';
|
|
9
9
|
import { getLyricsHeaderLength } from './lyrics3/Lyrics3.js';
|
|
10
|
+
export { LyricsContentType, TimestampFormat } from './type.js';
|
|
10
11
|
/**
|
|
11
12
|
* Parse Web API File
|
|
12
13
|
* Requires Blob to be able to stream using a ReadableStreamBYOBReader, only available since Node.js ≥ 20
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ID3v2MajorVersion } from './ID3v2Token.js';
|
|
1
|
+
import { ID3v2MajorVersion, ITextEncoding } from './ID3v2Token.js';
|
|
2
2
|
import { IWarningCollector } from '../common/MetadataCollector.js';
|
|
3
3
|
export declare function parseGenre(origVal: string): string[];
|
|
4
4
|
export declare class FrameParser {
|
|
@@ -11,6 +11,10 @@ export declare class FrameParser {
|
|
|
11
11
|
*/
|
|
12
12
|
constructor(major: ID3v2MajorVersion, warningCollector: IWarningCollector);
|
|
13
13
|
readData(uint8Array: Uint8Array, type: string, includeCovers: boolean): any;
|
|
14
|
+
protected static readNullTerminatedString(uint8Array: Uint8Array, encoding: ITextEncoding): {
|
|
15
|
+
text: string;
|
|
16
|
+
len: number;
|
|
17
|
+
};
|
|
14
18
|
protected static fixPictureMimeType(pictureType: string): string;
|
|
15
19
|
/**
|
|
16
20
|
* Converts TMCL (Musician credits list) or TIPL (Involved people list)
|
package/lib/id3v2/FrameParser.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import initDebug from 'debug';
|
|
2
2
|
import * as Token from 'token-types';
|
|
3
3
|
import * as util from '../common/Util.js';
|
|
4
|
-
import { AttachedPictureType, TextEncodingToken } from './ID3v2Token.js';
|
|
4
|
+
import { AttachedPictureType, TextEncodingToken, SyncTextHeader, TextHeader } from './ID3v2Token.js';
|
|
5
5
|
import { Genres } from '../id3v1/ID3v1Parser.js';
|
|
6
6
|
const debug = initDebug('music-metadata:id3v2:frame-parser');
|
|
7
7
|
const defaultEnc = 'latin1'; // latin1 == iso-8859-1;
|
|
@@ -75,7 +75,6 @@ export class FrameParser {
|
|
|
75
75
|
let output = []; // ToDo
|
|
76
76
|
const nullTerminatorLength = FrameParser.getNullTerminatorLength(encoding);
|
|
77
77
|
let fzero;
|
|
78
|
-
const out = {};
|
|
79
78
|
debug(`Parsing tag type=${type}, encoding=${encoding}, bom=${bom}`);
|
|
80
79
|
switch (type !== 'TXXX' && type[0] === 'T' ? 'T*' : type) {
|
|
81
80
|
case 'T*': // 4.2.1. Text information frames - details
|
|
@@ -168,31 +167,49 @@ export class FrameParser {
|
|
|
168
167
|
output = Token.UINT32_BE.get(uint8Array, 0);
|
|
169
168
|
break;
|
|
170
169
|
case 'SYLT':
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
170
|
+
const syltHeader = SyncTextHeader.get(uint8Array, 0);
|
|
171
|
+
offset += SyncTextHeader.len;
|
|
172
|
+
const result = {
|
|
173
|
+
descriptor: '',
|
|
174
|
+
language: syltHeader.language,
|
|
175
|
+
contentType: syltHeader.contentType,
|
|
176
|
+
timeStampFormat: syltHeader.timeStampFormat,
|
|
177
|
+
syncText: []
|
|
178
|
+
};
|
|
179
|
+
let readSyllables = false;
|
|
178
180
|
while (offset < length) {
|
|
179
|
-
const
|
|
180
|
-
offset +=
|
|
181
|
-
|
|
181
|
+
const nullStr = FrameParser.readNullTerminatedString(uint8Array.subarray(offset), syltHeader.encoding);
|
|
182
|
+
offset += nullStr.len;
|
|
183
|
+
if (readSyllables) {
|
|
184
|
+
const timestamp = Token.UINT32_BE.get(uint8Array, offset);
|
|
185
|
+
offset += Token.UINT32_BE.len;
|
|
186
|
+
result.syncText.push({
|
|
187
|
+
text: nullStr.text,
|
|
188
|
+
timestamp
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
result.descriptor = nullStr.text;
|
|
193
|
+
readSyllables = true;
|
|
194
|
+
}
|
|
182
195
|
}
|
|
196
|
+
output = result;
|
|
183
197
|
break;
|
|
184
198
|
case 'ULT':
|
|
185
199
|
case 'USLT':
|
|
186
200
|
case 'COM':
|
|
187
201
|
case 'COMM':
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
offset
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
202
|
+
const textHeader = TextHeader.get(uint8Array, offset);
|
|
203
|
+
offset += TextHeader.len;
|
|
204
|
+
const descriptorStr = FrameParser.readNullTerminatedString(uint8Array.subarray(offset), textHeader.encoding);
|
|
205
|
+
offset += descriptorStr.len;
|
|
206
|
+
const textStr = FrameParser.readNullTerminatedString(uint8Array.subarray(offset), textHeader.encoding);
|
|
207
|
+
const comment = {
|
|
208
|
+
language: textHeader.language,
|
|
209
|
+
descriptor: descriptorStr.text,
|
|
210
|
+
text: textStr.text
|
|
211
|
+
};
|
|
212
|
+
output = comment;
|
|
196
213
|
break;
|
|
197
214
|
case 'UFID':
|
|
198
215
|
output = FrameParser.readIdentifierAndData(uint8Array, offset, length, defaultEnc);
|
|
@@ -265,6 +282,15 @@ export class FrameParser {
|
|
|
265
282
|
}
|
|
266
283
|
return output;
|
|
267
284
|
}
|
|
285
|
+
static readNullTerminatedString(uint8Array, encoding) {
|
|
286
|
+
let offset = encoding.bom ? 2 : 0;
|
|
287
|
+
const txt = uint8Array.slice(offset, offset = util.findZero(uint8Array, offset, uint8Array.length, encoding.encoding));
|
|
288
|
+
offset += encoding.encoding === 'utf-16le' ? 2 : 1;
|
|
289
|
+
return {
|
|
290
|
+
text: util.decodeString(txt, encoding.encoding),
|
|
291
|
+
len: offset
|
|
292
|
+
};
|
|
293
|
+
}
|
|
268
294
|
static fixPictureMimeType(pictureType) {
|
|
269
295
|
pictureType = pictureType.toLocaleLowerCase();
|
|
270
296
|
switch (pictureType) {
|
|
@@ -27,12 +27,6 @@ export const id3v22TagMap = {
|
|
|
27
27
|
TEN: 'encodedby',
|
|
28
28
|
TSS: 'encodersettings',
|
|
29
29
|
WAR: 'website',
|
|
30
|
-
'COM:iTunPGAP': 'gapless'
|
|
31
|
-
/* ToDo: iTunes tags:
|
|
32
|
-
'COM:iTunNORM': ,
|
|
33
|
-
'COM:iTunSMPB': 'encoder delay',
|
|
34
|
-
'COM:iTunes_CDDB_IDs'
|
|
35
|
-
*/ ,
|
|
36
30
|
PCS: 'podcast',
|
|
37
31
|
TCP: "compilation",
|
|
38
32
|
TDR: 'date',
|
|
@@ -155,7 +155,6 @@ export class ID3v24TagMapper extends CaseInsensitiveTagMap {
|
|
|
155
155
|
* @param warnings Wil be used to register (collect) warnings
|
|
156
156
|
*/
|
|
157
157
|
postMap(tag, warnings) {
|
|
158
|
-
var _a, _b;
|
|
159
158
|
switch (tag.id) {
|
|
160
159
|
case 'UFID': // decode MusicBrainz Recording Id
|
|
161
160
|
if (tag.value.owner_identifier === 'http://musicbrainz.org') {
|
|
@@ -178,15 +177,9 @@ export class ID3v24TagMapper extends CaseInsensitiveTagMap {
|
|
|
178
177
|
warnings.addWarning(`Unknown PRIV owner-identifier: ${tag.value.owner_identifier}`);
|
|
179
178
|
}
|
|
180
179
|
break;
|
|
181
|
-
case 'COMM':
|
|
182
|
-
tag.value = (_a = tag.value) === null || _a === void 0 ? void 0 : _a.text;
|
|
183
|
-
break;
|
|
184
180
|
case 'POPM':
|
|
185
181
|
tag.value = ID3v24TagMapper.toRating(tag.value);
|
|
186
182
|
break;
|
|
187
|
-
case 'USLT':
|
|
188
|
-
tag.value = (_b = tag.value) === null || _b === void 0 ? void 0 : _b.text;
|
|
189
|
-
break;
|
|
190
183
|
default:
|
|
191
184
|
break;
|
|
192
185
|
}
|
|
@@ -22,6 +22,7 @@ export declare class ID3v2Parser {
|
|
|
22
22
|
parseExtendedHeader(): Promise<void>;
|
|
23
23
|
parseExtendedHeaderData(dataRemaining: number, extendedHeaderSize: number): Promise<void>;
|
|
24
24
|
parseId3Data(dataLen: number): Promise<void>;
|
|
25
|
+
private handleTag;
|
|
25
26
|
private addTag;
|
|
26
27
|
private parseMetadata;
|
|
27
28
|
private readFrameHeader;
|
package/lib/id3v2/ID3v2Parser.js
CHANGED
|
@@ -97,25 +97,20 @@ export class ID3v2Parser {
|
|
|
97
97
|
async parseId3Data(dataLen) {
|
|
98
98
|
const uint8Array = await this.tokenizer.readToken(new Token.Uint8ArrayType(dataLen));
|
|
99
99
|
for (const tag of this.parseMetadata(uint8Array)) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
else if (tag.id === 'COMM') {
|
|
109
|
-
await Promise.all(tag.value.map(value => this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, value.description), value)));
|
|
110
|
-
}
|
|
111
|
-
else if (Array.isArray(tag.value)) {
|
|
112
|
-
await Promise.all(tag.value.map(value => this.addTag(tag.id, value)));
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
await this.addTag(tag.id, tag.value);
|
|
100
|
+
switch (tag.id) {
|
|
101
|
+
case 'TXXX':
|
|
102
|
+
if (tag.value) {
|
|
103
|
+
await this.handleTag(tag, tag.value.text, () => tag.value.description);
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
107
|
+
await (Array.isArray(tag.value) ? Promise.all(tag.value.map(value => this.addTag(tag.id, value))) : this.addTag(tag.id, tag.value));
|
|
116
108
|
}
|
|
117
109
|
}
|
|
118
110
|
}
|
|
111
|
+
async handleTag(tag, values, descriptor, resolveValue = value => value) {
|
|
112
|
+
await Promise.all(values.map(value => this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, descriptor(value)), resolveValue(value))));
|
|
113
|
+
}
|
|
119
114
|
async addTag(id, value) {
|
|
120
115
|
await this.metadata.addTag(this.headerType, id, value);
|
|
121
116
|
}
|
|
@@ -34,6 +34,23 @@ export interface IExtendedHeader {
|
|
|
34
34
|
sizeOfPadding: number;
|
|
35
35
|
crcDataPresent: boolean;
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* https://id3.org/id3v2.3.0#Synchronised_lyrics.2Ftext
|
|
39
|
+
*/
|
|
40
|
+
export declare enum LyricsContentType {
|
|
41
|
+
other = 0,
|
|
42
|
+
lyrics = 1,
|
|
43
|
+
text = 2,
|
|
44
|
+
movement_part = 3,
|
|
45
|
+
events = 4,
|
|
46
|
+
chord = 5,
|
|
47
|
+
trivia_pop = 6
|
|
48
|
+
}
|
|
49
|
+
export declare enum TimestampFormat {
|
|
50
|
+
notSynchronized0 = 0,
|
|
51
|
+
mpegFrameNumber = 1,
|
|
52
|
+
milliseconds = 2
|
|
53
|
+
}
|
|
37
54
|
/**
|
|
38
55
|
* 28 bits (representing up to 256MB) integer, the msb is 0 to avoid 'false syncsignals'.
|
|
39
56
|
* 4 * %0xxxxxxx
|
|
@@ -71,3 +88,25 @@ export interface ITextEncoding {
|
|
|
71
88
|
bom?: boolean;
|
|
72
89
|
}
|
|
73
90
|
export declare const TextEncodingToken: IGetToken<ITextEncoding>;
|
|
91
|
+
/**
|
|
92
|
+
* `USLT` frame fields
|
|
93
|
+
*/
|
|
94
|
+
export interface ITextHeader {
|
|
95
|
+
encoding: ITextEncoding;
|
|
96
|
+
language: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Used to read first portion of `SYLT` frame
|
|
100
|
+
*/
|
|
101
|
+
export declare const TextHeader: IGetToken<ITextHeader>;
|
|
102
|
+
/**
|
|
103
|
+
* SYLT` frame fields
|
|
104
|
+
*/
|
|
105
|
+
export interface ISyncTextHeader extends ITextHeader {
|
|
106
|
+
contentType: LyricsContentType;
|
|
107
|
+
timeStampFormat: TimestampFormat;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Used to read first portion of `SYLT` frame
|
|
111
|
+
*/
|
|
112
|
+
export declare const SyncTextHeader: IGetToken<ISyncTextHeader>;
|
package/lib/id3v2/ID3v2Token.js
CHANGED
|
@@ -28,6 +28,25 @@ export var AttachedPictureType;
|
|
|
28
28
|
AttachedPictureType[AttachedPictureType["Band/artist logotype"] = 19] = "Band/artist logotype";
|
|
29
29
|
AttachedPictureType[AttachedPictureType["Publisher/Studio logotype"] = 20] = "Publisher/Studio logotype";
|
|
30
30
|
})(AttachedPictureType || (AttachedPictureType = {}));
|
|
31
|
+
/**
|
|
32
|
+
* https://id3.org/id3v2.3.0#Synchronised_lyrics.2Ftext
|
|
33
|
+
*/
|
|
34
|
+
export var LyricsContentType;
|
|
35
|
+
(function (LyricsContentType) {
|
|
36
|
+
LyricsContentType[LyricsContentType["other"] = 0] = "other";
|
|
37
|
+
LyricsContentType[LyricsContentType["lyrics"] = 1] = "lyrics";
|
|
38
|
+
LyricsContentType[LyricsContentType["text"] = 2] = "text";
|
|
39
|
+
LyricsContentType[LyricsContentType["movement_part"] = 3] = "movement_part";
|
|
40
|
+
LyricsContentType[LyricsContentType["events"] = 4] = "events";
|
|
41
|
+
LyricsContentType[LyricsContentType["chord"] = 5] = "chord";
|
|
42
|
+
LyricsContentType[LyricsContentType["trivia_pop"] = 6] = "trivia_pop";
|
|
43
|
+
})(LyricsContentType || (LyricsContentType = {}));
|
|
44
|
+
export var TimestampFormat;
|
|
45
|
+
(function (TimestampFormat) {
|
|
46
|
+
TimestampFormat[TimestampFormat["notSynchronized0"] = 0] = "notSynchronized0";
|
|
47
|
+
TimestampFormat[TimestampFormat["mpegFrameNumber"] = 1] = "mpegFrameNumber";
|
|
48
|
+
TimestampFormat[TimestampFormat["milliseconds"] = 2] = "milliseconds";
|
|
49
|
+
})(TimestampFormat || (TimestampFormat = {}));
|
|
31
50
|
/**
|
|
32
51
|
* 28 bits (representing up to 256MB) integer, the msb is 0 to avoid 'false syncsignals'.
|
|
33
52
|
* 4 * %0xxxxxxx
|
|
@@ -101,3 +120,31 @@ export const TextEncodingToken = {
|
|
|
101
120
|
}
|
|
102
121
|
}
|
|
103
122
|
};
|
|
123
|
+
/**
|
|
124
|
+
* Used to read first portion of `SYLT` frame
|
|
125
|
+
*/
|
|
126
|
+
export const TextHeader = {
|
|
127
|
+
len: 4,
|
|
128
|
+
get: (uint8Array, off) => {
|
|
129
|
+
return {
|
|
130
|
+
encoding: TextEncodingToken.get(uint8Array, off),
|
|
131
|
+
language: new Token.StringType(3, 'latin1').get(uint8Array, off + 1)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Used to read first portion of `SYLT` frame
|
|
137
|
+
*/
|
|
138
|
+
export const SyncTextHeader = {
|
|
139
|
+
len: 6,
|
|
140
|
+
get: (uint8Array, off) => {
|
|
141
|
+
const text = TextHeader.get(uint8Array, off);
|
|
142
|
+
return {
|
|
143
|
+
encoding: text.encoding,
|
|
144
|
+
language: text.language,
|
|
145
|
+
timeStampFormat: Token.UINT8.get(uint8Array, off + 4),
|
|
146
|
+
contentType: Token.UINT8.get(uint8Array, off + 5)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=ID3v2Token.js.map
|
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import * as Stream from 'stream';
|
|
5
5
|
import * as strtok3 from 'strtok3';
|
|
6
6
|
import { IAudioMetadata, IOptions } from './type.js';
|
|
7
|
-
export { IAudioMetadata, IOptions, ITag, INativeTagDict, ICommonTagsResult, IFormat, IPicture, IRatio, IChapter } from './type.js';
|
|
7
|
+
export { IAudioMetadata, IOptions, ITag, INativeTagDict, ICommonTagsResult, IFormat, IPicture, IRatio, IChapter, ILyricsTag, LyricsContentType, TimestampFormat } from './type.js';
|
|
8
8
|
export { parseFromTokenizer, parseBuffer, parseBlob, parseWebStream, selectCover, orderTags, ratingToStars, IFileInfo } from './core.js';
|
|
9
9
|
/**
|
|
10
10
|
* Parse audio from Node Stream.Readable
|
package/lib/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import initDebug from 'debug';
|
|
|
6
6
|
import { parseFromTokenizer, scanAppendingHeaders } from './core.js';
|
|
7
7
|
import { ParserFactory } from './ParserFactory.js';
|
|
8
8
|
import { RandomFileReader } from './common/RandomFileReader.js';
|
|
9
|
+
export { LyricsContentType, TimestampFormat } from './type.js';
|
|
9
10
|
export { parseFromTokenizer, parseBuffer, parseBlob, parseWebStream, selectCover, orderTags, ratingToStars } from './core.js';
|
|
10
11
|
const debug = initDebug('music-metadata:parser');
|
|
11
12
|
/**
|
package/lib/type.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { GenericTagId, TagType } from './common/GenericTagTypes.js';
|
|
2
2
|
import { IFooter } from './apev2/APEv2Token.js';
|
|
3
3
|
import { TrackType } from './matroska/types.js';
|
|
4
|
+
import { LyricsContentType, TimestampFormat } from './id3v2/ID3v2Token.js';
|
|
4
5
|
export { TrackType } from './matroska/types.js';
|
|
6
|
+
export { LyricsContentType, TimestampFormat } from './id3v2/ID3v2Token.js';
|
|
5
7
|
/**
|
|
6
8
|
* Attached picture, typically used for cover art
|
|
7
9
|
*/
|
|
@@ -92,7 +94,7 @@ export interface ICommonTagsResult {
|
|
|
92
94
|
/**
|
|
93
95
|
* List of comments
|
|
94
96
|
*/
|
|
95
|
-
comment?:
|
|
97
|
+
comment?: IComment[];
|
|
96
98
|
/**
|
|
97
99
|
* Genre
|
|
98
100
|
*/
|
|
@@ -106,9 +108,9 @@ export interface ICommonTagsResult {
|
|
|
106
108
|
*/
|
|
107
109
|
composer?: string[];
|
|
108
110
|
/**
|
|
109
|
-
*
|
|
111
|
+
* Synchronized lyrics
|
|
110
112
|
*/
|
|
111
|
-
lyrics?:
|
|
113
|
+
lyrics?: ILyricsTag[];
|
|
112
114
|
/**
|
|
113
115
|
* Album title, formatted for alphabetic ordering
|
|
114
116
|
*/
|
|
@@ -593,3 +595,24 @@ export interface IRandomReader {
|
|
|
593
595
|
*/
|
|
594
596
|
randomRead(buffer: Uint8Array, offset: number, length: number, position: number): Promise<number>;
|
|
595
597
|
}
|
|
598
|
+
interface ILyricsText {
|
|
599
|
+
text: string;
|
|
600
|
+
timestamp?: number;
|
|
601
|
+
}
|
|
602
|
+
export interface IComment {
|
|
603
|
+
descriptor?: string;
|
|
604
|
+
language?: string;
|
|
605
|
+
text?: string;
|
|
606
|
+
}
|
|
607
|
+
export interface ILyricsTag extends IComment {
|
|
608
|
+
contentType: LyricsContentType;
|
|
609
|
+
timeStampFormat: TimestampFormat;
|
|
610
|
+
/**
|
|
611
|
+
* Un-synchronized lyrics
|
|
612
|
+
*/
|
|
613
|
+
text?: string;
|
|
614
|
+
/**
|
|
615
|
+
* Synchronized lyrics
|
|
616
|
+
*/
|
|
617
|
+
syncText: ILyricsText[];
|
|
618
|
+
}
|
package/lib/type.js
CHANGED
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": "
|
|
4
|
+
"version": "10.0.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Borewit",
|
|
7
7
|
"url": "https://github.com/Borewit"
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"compile-test": "tsc -p test",
|
|
85
85
|
"compile-doc": "tsc -p doc-gen",
|
|
86
86
|
"compile": "npm run compile-src && npm run compile-test && npm run compile-doc",
|
|
87
|
-
"eslint": "eslint lib
|
|
87
|
+
"eslint": "eslint lib test doc-gen",
|
|
88
88
|
"lint-md": "remark -u preset-lint-markdown-style-guide .",
|
|
89
89
|
"lint": "npm run lint-md && npm run eslint",
|
|
90
90
|
"test": "mocha",
|
|
@@ -105,25 +105,29 @@
|
|
|
105
105
|
"uint8array-extras": "^1.4.0"
|
|
106
106
|
},
|
|
107
107
|
"devDependencies": {
|
|
108
|
+
"@eslint/compat": "^1.1.1",
|
|
109
|
+
"@eslint/eslintrc": "^3.1.0",
|
|
110
|
+
"@eslint/js": "^9.7.0",
|
|
108
111
|
"@types/chai": "^4.3.16",
|
|
109
112
|
"@types/chai-as-promised": "^7.1.8",
|
|
110
113
|
"@types/debug": "^4.1.12",
|
|
111
114
|
"@types/file-type": "^10.9.1",
|
|
112
115
|
"@types/mocha": "^10.0.7",
|
|
113
116
|
"@types/node": "^20.14.11",
|
|
114
|
-
"@typescript-eslint/eslint-plugin": "^7.16.
|
|
115
|
-
"@typescript-eslint/parser": "^7.16.
|
|
117
|
+
"@typescript-eslint/eslint-plugin": "^7.16.1",
|
|
118
|
+
"@typescript-eslint/parser": "^7.16.1",
|
|
116
119
|
"c8": "^10.1.2",
|
|
117
120
|
"chai": "^5.1.1",
|
|
118
121
|
"chai-as-promised": "^8.0.0",
|
|
119
122
|
"del-cli": "^5.1.0",
|
|
120
|
-
"eslint": "^
|
|
123
|
+
"eslint": "^9.7.0",
|
|
121
124
|
"eslint-config-prettier": "^9.1.0",
|
|
122
125
|
"eslint-import-resolver-typescript": "^3.6.1",
|
|
123
126
|
"eslint-plugin-import": "^2.29.1",
|
|
124
127
|
"eslint-plugin-jsdoc": "^48.7.0",
|
|
125
128
|
"eslint-plugin-node": "^11.1.0",
|
|
126
129
|
"eslint-plugin-unicorn": "^54.0.0",
|
|
130
|
+
"globals": "^15.8.0",
|
|
127
131
|
"mime": "^4.0.4",
|
|
128
132
|
"mocha": "^10.6.0",
|
|
129
133
|
"npm-run-all": "^4.1.5",
|