agdi 3.3.5 → 3.3.7
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/README.md +13 -0
- package/dist/APEv2Parser-EU45AV6X.js +14 -0
- package/dist/AiffParser-FOX7GQ42.js +189 -0
- package/dist/AsfParser-HD5CSGIO.js +610 -0
- package/dist/DsdiffParser-OJREDMBI.js +188 -0
- package/dist/DsfParser-2YL4ARJ7.js +110 -0
- package/dist/FlacParser-IVV4RYF6.js +15 -0
- package/dist/MP4Parser-NLX4A2YN.js +1140 -0
- package/dist/MatroskaParser-4OEK43GF.js +654 -0
- package/dist/MpegParser-PXKEUF2B.js +642 -0
- package/dist/MusepackParser-54QGYRLY.js +322 -0
- package/dist/OggParser-KRV5QCGZ.js +435 -0
- package/dist/WavPackParser-XPZSQFVS.js +203 -0
- package/dist/WaveParser-27IS2RAI.js +294 -0
- package/dist/chunk-2B4QMSZW.js +311 -0
- package/dist/chunk-3JKZUGPJ.js +70 -0
- package/dist/chunk-4VNS5WPM.js +42 -0
- package/dist/chunk-65JVFJ3X.js +729 -0
- package/dist/chunk-6OKLAJRQ.js +0 -0
- package/dist/chunk-AGSFUVRG.js +439 -0
- package/dist/chunk-GD35BJSH.js +177 -0
- package/dist/chunk-HNLU36CC.js +702 -0
- package/dist/{chunk-M2FF7ETI.js → chunk-J6OLLWVT.js} +1 -1
- package/dist/chunk-LREP5CZP.js +146 -0
- package/dist/chunk-M54HVABG.js +34 -0
- package/dist/{chunk-S45VXJEO.js → chunk-OPFFFAQC.js} +19 -1
- package/dist/chunk-VGOIHW7D.js +1529 -0
- package/dist/chunk-YIHDW7JC.js +314 -0
- package/dist/config-D3QBUN2Y.js +13 -0
- package/dist/{config-ZFU7TSU2.js → config-K2XM6D4Z.js} +3 -2
- package/dist/{event-bus-Q3WCETQQ.js → event-bus-MO5SFUME.js} +1 -0
- package/dist/index.js +3273 -1274
- package/dist/lib-2XISBYT3.js +144950 -0
- package/dist/lib-HCGLI2GJ.js +4161 -0
- package/dist/{telemetry-service-OHU5NKON.js → telemetry-service-76YPOPDM.js} +8 -4
- package/package.json +6 -3
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Genres
|
|
3
|
+
} from "./chunk-2B4QMSZW.js";
|
|
4
|
+
import {
|
|
5
|
+
AttachedPictureType,
|
|
6
|
+
ExtendedHeader,
|
|
7
|
+
ID3v2Header,
|
|
8
|
+
SyncTextHeader,
|
|
9
|
+
TextEncodingToken,
|
|
10
|
+
TextHeader,
|
|
11
|
+
UINT32SYNCSAFE
|
|
12
|
+
} from "./chunk-LREP5CZP.js";
|
|
13
|
+
import {
|
|
14
|
+
decodeString,
|
|
15
|
+
decodeUintBE,
|
|
16
|
+
findZero,
|
|
17
|
+
getBit
|
|
18
|
+
} from "./chunk-GD35BJSH.js";
|
|
19
|
+
import {
|
|
20
|
+
UINT24_BE,
|
|
21
|
+
UINT32_BE,
|
|
22
|
+
UINT8,
|
|
23
|
+
Uint8ArrayType,
|
|
24
|
+
makeUnexpectedFileContentError,
|
|
25
|
+
require_src,
|
|
26
|
+
textDecode
|
|
27
|
+
} from "./chunk-VGOIHW7D.js";
|
|
28
|
+
import {
|
|
29
|
+
__toESM
|
|
30
|
+
} from "./chunk-4VNS5WPM.js";
|
|
31
|
+
|
|
32
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/id3v2/FrameParser.js
|
|
33
|
+
var import_debug = __toESM(require_src(), 1);
|
|
34
|
+
|
|
35
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/id3v2/ID3v2ChapterToken.js
|
|
36
|
+
var ChapterInfo = {
|
|
37
|
+
len: 16,
|
|
38
|
+
get: (buf, off) => {
|
|
39
|
+
const startOffset = UINT32_BE.get(buf, off + 8);
|
|
40
|
+
const endOffset = UINT32_BE.get(buf, off + 12);
|
|
41
|
+
return {
|
|
42
|
+
startTime: UINT32_BE.get(buf, off),
|
|
43
|
+
endTime: UINT32_BE.get(buf, off + 4),
|
|
44
|
+
startOffset: startOffset === 4294967295 ? void 0 : startOffset,
|
|
45
|
+
endOffset: endOffset === 4294967295 ? void 0 : endOffset
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/id3v2/FrameHeader.js
|
|
51
|
+
function getFrameHeaderLength(majorVer) {
|
|
52
|
+
switch (majorVer) {
|
|
53
|
+
case 2:
|
|
54
|
+
return 6;
|
|
55
|
+
case 3:
|
|
56
|
+
case 4:
|
|
57
|
+
return 10;
|
|
58
|
+
default:
|
|
59
|
+
throw makeUnexpectedMajorVersionError(majorVer);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function readFrameFlags(b) {
|
|
63
|
+
return {
|
|
64
|
+
status: {
|
|
65
|
+
tag_alter_preservation: getBit(b, 0, 6),
|
|
66
|
+
file_alter_preservation: getBit(b, 0, 5),
|
|
67
|
+
read_only: getBit(b, 0, 4)
|
|
68
|
+
},
|
|
69
|
+
format: {
|
|
70
|
+
grouping_identity: getBit(b, 1, 7),
|
|
71
|
+
compression: getBit(b, 1, 3),
|
|
72
|
+
encryption: getBit(b, 1, 2),
|
|
73
|
+
unsynchronisation: getBit(b, 1, 1),
|
|
74
|
+
data_length_indicator: getBit(b, 1, 0)
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function readFrameHeader(uint8Array, majorVer, warningCollector) {
|
|
79
|
+
switch (majorVer) {
|
|
80
|
+
case 2:
|
|
81
|
+
return parseFrameHeaderV22(uint8Array, majorVer, warningCollector);
|
|
82
|
+
case 3:
|
|
83
|
+
case 4:
|
|
84
|
+
return parseFrameHeaderV23V24(uint8Array, majorVer, warningCollector);
|
|
85
|
+
default:
|
|
86
|
+
throw makeUnexpectedMajorVersionError(majorVer);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function parseFrameHeaderV22(uint8Array, majorVer, warningCollector) {
|
|
90
|
+
const header = {
|
|
91
|
+
id: textDecode(uint8Array.subarray(0, 3), "ascii"),
|
|
92
|
+
length: UINT24_BE.get(uint8Array, 3)
|
|
93
|
+
};
|
|
94
|
+
if (!header.id.match(/^[A-Z0-9]{3}$/)) {
|
|
95
|
+
warningCollector.addWarning(`Invalid ID3v2.${majorVer} frame-header-ID: ${header.id}`);
|
|
96
|
+
}
|
|
97
|
+
return header;
|
|
98
|
+
}
|
|
99
|
+
function parseFrameHeaderV23V24(uint8Array, majorVer, warningCollector) {
|
|
100
|
+
const header = {
|
|
101
|
+
id: textDecode(uint8Array.subarray(0, 4), "ascii"),
|
|
102
|
+
length: (majorVer === 4 ? UINT32SYNCSAFE : UINT32_BE).get(uint8Array, 4),
|
|
103
|
+
flags: readFrameFlags(uint8Array.subarray(8, 10))
|
|
104
|
+
};
|
|
105
|
+
if (!header.id.match(/^[A-Z0-9]{4}$/)) {
|
|
106
|
+
warningCollector.addWarning(`Invalid ID3v2.${majorVer} frame-header-ID: ${header.id}`);
|
|
107
|
+
}
|
|
108
|
+
return header;
|
|
109
|
+
}
|
|
110
|
+
function makeUnexpectedMajorVersionError(majorVer) {
|
|
111
|
+
throw new Id3v2ContentError(`Unexpected majorVer: ${majorVer}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/id3v2/FrameParser.js
|
|
115
|
+
var debug = (0, import_debug.default)("music-metadata:id3v2:frame-parser");
|
|
116
|
+
var defaultEnc = "latin1";
|
|
117
|
+
var urlEnc = { encoding: defaultEnc, bom: false };
|
|
118
|
+
function parseGenre(origVal) {
|
|
119
|
+
const genres = [];
|
|
120
|
+
let code;
|
|
121
|
+
let word = "";
|
|
122
|
+
for (const c of origVal) {
|
|
123
|
+
if (typeof code === "string") {
|
|
124
|
+
if (c === "(" && code === "") {
|
|
125
|
+
word += "(";
|
|
126
|
+
code = void 0;
|
|
127
|
+
} else if (c === ")") {
|
|
128
|
+
if (word !== "") {
|
|
129
|
+
genres.push(word);
|
|
130
|
+
word = "";
|
|
131
|
+
}
|
|
132
|
+
const genre = parseGenreCode(code);
|
|
133
|
+
if (genre) {
|
|
134
|
+
genres.push(genre);
|
|
135
|
+
}
|
|
136
|
+
code = void 0;
|
|
137
|
+
} else
|
|
138
|
+
code += c;
|
|
139
|
+
} else if (c === "(") {
|
|
140
|
+
code = "";
|
|
141
|
+
} else {
|
|
142
|
+
word += c;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (word) {
|
|
146
|
+
if (genres.length === 0 && word.match(/^\d*$/)) {
|
|
147
|
+
word = parseGenreCode(word);
|
|
148
|
+
}
|
|
149
|
+
if (word) {
|
|
150
|
+
genres.push(word);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return genres;
|
|
154
|
+
}
|
|
155
|
+
function parseGenreCode(code) {
|
|
156
|
+
if (code === "RX")
|
|
157
|
+
return "Remix";
|
|
158
|
+
if (code === "CR")
|
|
159
|
+
return "Cover";
|
|
160
|
+
if (code.match(/^\d*$/)) {
|
|
161
|
+
return Genres[Number.parseInt(code, 10)];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
var FrameParser = class _FrameParser {
|
|
165
|
+
/**
|
|
166
|
+
* Create id3v2 frame parser
|
|
167
|
+
* @param major - Major version, e.g. (4) for id3v2.4
|
|
168
|
+
* @param warningCollector - Used to collect decode issue
|
|
169
|
+
*/
|
|
170
|
+
constructor(major, warningCollector) {
|
|
171
|
+
this.major = major;
|
|
172
|
+
this.warningCollector = warningCollector;
|
|
173
|
+
}
|
|
174
|
+
readData(uint8Array, type, includeCovers) {
|
|
175
|
+
if (uint8Array.length === 0) {
|
|
176
|
+
this.warningCollector.addWarning(`id3v2.${this.major} header has empty tag type=${type}`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const { encoding, bom } = TextEncodingToken.get(uint8Array, 0);
|
|
180
|
+
const length = uint8Array.length;
|
|
181
|
+
let offset = 0;
|
|
182
|
+
let output = [];
|
|
183
|
+
const nullTerminatorLength = _FrameParser.getNullTerminatorLength(encoding);
|
|
184
|
+
let fzero;
|
|
185
|
+
debug(`Parsing tag type=${type}, encoding=${encoding}, bom=${bom}`);
|
|
186
|
+
switch (type !== "TXXX" && type[0] === "T" ? "T*" : type) {
|
|
187
|
+
case "T*":
|
|
188
|
+
// 4.2.1. Text information frames - details
|
|
189
|
+
case "GRP1":
|
|
190
|
+
// iTunes-specific ID3v2 grouping field
|
|
191
|
+
case "GP1":
|
|
192
|
+
// iTunes-specific ID3v2.2 grouping field
|
|
193
|
+
case "IPLS":
|
|
194
|
+
// v2.3: Involved people list
|
|
195
|
+
case "MVIN":
|
|
196
|
+
case "MVNM":
|
|
197
|
+
case "PCS":
|
|
198
|
+
case "PCST": {
|
|
199
|
+
let text;
|
|
200
|
+
try {
|
|
201
|
+
text = _FrameParser.trimNullPadding(decodeString(uint8Array.subarray(1), encoding));
|
|
202
|
+
} catch (error) {
|
|
203
|
+
if (error instanceof Error) {
|
|
204
|
+
this.warningCollector.addWarning(`id3v2.${this.major} type=${type} header has invalid string value: ${error.message}`);
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
switch (type) {
|
|
210
|
+
case "TMCL":
|
|
211
|
+
// Musician credits list
|
|
212
|
+
case "TIPL":
|
|
213
|
+
// Involved people list
|
|
214
|
+
case "IPLS":
|
|
215
|
+
output = _FrameParser.functionList(this.splitValue(type, text));
|
|
216
|
+
break;
|
|
217
|
+
case "TRK":
|
|
218
|
+
case "TRCK":
|
|
219
|
+
case "TPOS":
|
|
220
|
+
case "TIT1":
|
|
221
|
+
case "TIT2":
|
|
222
|
+
case "TIT3":
|
|
223
|
+
output = text;
|
|
224
|
+
break;
|
|
225
|
+
case "TCOM":
|
|
226
|
+
case "TEXT":
|
|
227
|
+
case "TOLY":
|
|
228
|
+
case "TOPE":
|
|
229
|
+
case "TPE1":
|
|
230
|
+
case "TSRC":
|
|
231
|
+
output = this.splitValue(type, text);
|
|
232
|
+
break;
|
|
233
|
+
case "TCO":
|
|
234
|
+
case "TCON":
|
|
235
|
+
output = this.splitValue(type, text).map((v) => parseGenre(v)).reduce((acc, val) => acc.concat(val), []);
|
|
236
|
+
break;
|
|
237
|
+
case "PCS":
|
|
238
|
+
case "PCST":
|
|
239
|
+
output = this.major >= 4 ? this.splitValue(type, text) : [text];
|
|
240
|
+
output = Array.isArray(output) && output[0] === "" ? 1 : 0;
|
|
241
|
+
break;
|
|
242
|
+
default:
|
|
243
|
+
output = this.major >= 4 ? this.splitValue(type, text) : [text];
|
|
244
|
+
}
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
case "TXXX": {
|
|
248
|
+
const idAndData = _FrameParser.readIdentifierAndData(uint8Array.subarray(1), encoding);
|
|
249
|
+
output = {
|
|
250
|
+
description: idAndData.id,
|
|
251
|
+
text: this.splitValue(type, decodeString(idAndData.data, encoding).replace(/\x00+$/, ""))
|
|
252
|
+
};
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
case "PIC":
|
|
256
|
+
case "APIC":
|
|
257
|
+
if (includeCovers) {
|
|
258
|
+
const pic = {};
|
|
259
|
+
uint8Array = uint8Array.subarray(1);
|
|
260
|
+
switch (this.major) {
|
|
261
|
+
case 2:
|
|
262
|
+
pic.format = decodeString(uint8Array.subarray(0, 3), "latin1");
|
|
263
|
+
uint8Array = uint8Array.subarray(3);
|
|
264
|
+
break;
|
|
265
|
+
case 3:
|
|
266
|
+
case 4:
|
|
267
|
+
fzero = findZero(uint8Array, defaultEnc);
|
|
268
|
+
pic.format = decodeString(uint8Array.subarray(0, fzero), defaultEnc);
|
|
269
|
+
uint8Array = uint8Array.subarray(fzero + 1);
|
|
270
|
+
break;
|
|
271
|
+
default:
|
|
272
|
+
throw makeUnexpectedMajorVersionError2(this.major);
|
|
273
|
+
}
|
|
274
|
+
pic.format = _FrameParser.fixPictureMimeType(pic.format);
|
|
275
|
+
pic.type = AttachedPictureType[uint8Array[0]];
|
|
276
|
+
uint8Array = uint8Array.subarray(1);
|
|
277
|
+
fzero = findZero(uint8Array, encoding);
|
|
278
|
+
pic.description = decodeString(uint8Array.subarray(0, fzero), encoding);
|
|
279
|
+
uint8Array = uint8Array.subarray(fzero + nullTerminatorLength);
|
|
280
|
+
pic.data = uint8Array;
|
|
281
|
+
output = pic;
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
case "CNT":
|
|
285
|
+
case "PCNT":
|
|
286
|
+
output = decodeUintBE(uint8Array);
|
|
287
|
+
break;
|
|
288
|
+
case "SYLT": {
|
|
289
|
+
const syltHeader = SyncTextHeader.get(uint8Array, 0);
|
|
290
|
+
uint8Array = uint8Array.subarray(SyncTextHeader.len);
|
|
291
|
+
const result = {
|
|
292
|
+
descriptor: "",
|
|
293
|
+
language: syltHeader.language,
|
|
294
|
+
contentType: syltHeader.contentType,
|
|
295
|
+
timeStampFormat: syltHeader.timeStampFormat,
|
|
296
|
+
syncText: []
|
|
297
|
+
};
|
|
298
|
+
let readSyllables = false;
|
|
299
|
+
while (uint8Array.length > 0) {
|
|
300
|
+
const nullStr = _FrameParser.readNullTerminatedString(uint8Array, syltHeader.encoding);
|
|
301
|
+
uint8Array = uint8Array.subarray(nullStr.len);
|
|
302
|
+
if (readSyllables) {
|
|
303
|
+
const timestamp = UINT32_BE.get(uint8Array, 0);
|
|
304
|
+
uint8Array = uint8Array.subarray(UINT32_BE.len);
|
|
305
|
+
result.syncText.push({
|
|
306
|
+
text: nullStr.text,
|
|
307
|
+
timestamp
|
|
308
|
+
});
|
|
309
|
+
} else {
|
|
310
|
+
result.descriptor = nullStr.text;
|
|
311
|
+
readSyllables = true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
output = result;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
case "ULT":
|
|
318
|
+
case "USLT":
|
|
319
|
+
case "COM":
|
|
320
|
+
case "COMM": {
|
|
321
|
+
const textHeader = TextHeader.get(uint8Array, offset);
|
|
322
|
+
offset += TextHeader.len;
|
|
323
|
+
const descriptorStr = _FrameParser.readNullTerminatedString(uint8Array.subarray(offset), textHeader.encoding);
|
|
324
|
+
offset += descriptorStr.len;
|
|
325
|
+
const textStr = _FrameParser.readNullTerminatedString(uint8Array.subarray(offset), textHeader.encoding);
|
|
326
|
+
const comment = {
|
|
327
|
+
language: textHeader.language,
|
|
328
|
+
descriptor: descriptorStr.text,
|
|
329
|
+
text: textStr.text
|
|
330
|
+
};
|
|
331
|
+
output = comment;
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
case "UFID": {
|
|
335
|
+
const ufid = _FrameParser.readIdentifierAndData(uint8Array, defaultEnc);
|
|
336
|
+
output = { owner_identifier: ufid.id, identifier: ufid.data };
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
case "PRIV": {
|
|
340
|
+
const priv = _FrameParser.readIdentifierAndData(uint8Array, defaultEnc);
|
|
341
|
+
output = { owner_identifier: priv.id, data: priv.data };
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
case "POPM": {
|
|
345
|
+
uint8Array = uint8Array.subarray(offset);
|
|
346
|
+
const emailStr = _FrameParser.readNullTerminatedString(uint8Array, urlEnc);
|
|
347
|
+
const email = emailStr.text;
|
|
348
|
+
uint8Array = uint8Array.subarray(emailStr.len);
|
|
349
|
+
if (uint8Array.length === 0) {
|
|
350
|
+
this.warningCollector.addWarning(`id3v2.${this.major} type=${type} POPM frame missing rating byte`);
|
|
351
|
+
output = { email, rating: 0, counter: void 0 };
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
const rating = UINT8.get(uint8Array, 0);
|
|
355
|
+
const counterBytes = uint8Array.subarray(UINT8.len);
|
|
356
|
+
output = {
|
|
357
|
+
email,
|
|
358
|
+
rating,
|
|
359
|
+
counter: counterBytes.length > 0 ? decodeUintBE(counterBytes) : void 0
|
|
360
|
+
};
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
case "GEOB": {
|
|
364
|
+
const encoding2 = TextEncodingToken.get(uint8Array, 0);
|
|
365
|
+
uint8Array = uint8Array.subarray(1);
|
|
366
|
+
const mimeTypeStr = _FrameParser.readNullTerminatedString(uint8Array, urlEnc);
|
|
367
|
+
const mimeType = mimeTypeStr.text;
|
|
368
|
+
uint8Array = uint8Array.subarray(mimeTypeStr.len);
|
|
369
|
+
const filenameStr = _FrameParser.readNullTerminatedString(uint8Array, encoding2);
|
|
370
|
+
const filename = filenameStr.text;
|
|
371
|
+
uint8Array = uint8Array.subarray(filenameStr.len);
|
|
372
|
+
const descriptionStr = _FrameParser.readNullTerminatedString(uint8Array, encoding2);
|
|
373
|
+
const description = descriptionStr.text;
|
|
374
|
+
uint8Array = uint8Array.subarray(descriptionStr.len);
|
|
375
|
+
const geob = {
|
|
376
|
+
type: mimeType,
|
|
377
|
+
filename,
|
|
378
|
+
description,
|
|
379
|
+
data: uint8Array
|
|
380
|
+
};
|
|
381
|
+
output = geob;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
// W-Frames:
|
|
385
|
+
case "WCOM":
|
|
386
|
+
case "WCOP":
|
|
387
|
+
case "WOAF":
|
|
388
|
+
case "WOAR":
|
|
389
|
+
case "WOAS":
|
|
390
|
+
case "WORS":
|
|
391
|
+
case "WPAY":
|
|
392
|
+
case "WPUB":
|
|
393
|
+
output = _FrameParser.readNullTerminatedString(uint8Array, urlEnc).text;
|
|
394
|
+
break;
|
|
395
|
+
case "WXXX": {
|
|
396
|
+
const encoding2 = TextEncodingToken.get(uint8Array, 0);
|
|
397
|
+
uint8Array = uint8Array.subarray(1);
|
|
398
|
+
const descriptionStr = _FrameParser.readNullTerminatedString(uint8Array, encoding2);
|
|
399
|
+
const description = descriptionStr.text;
|
|
400
|
+
uint8Array = uint8Array.subarray(descriptionStr.len);
|
|
401
|
+
output = { description, url: _FrameParser.trimNullPadding(decodeString(uint8Array, defaultEnc)) };
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
case "WFD":
|
|
405
|
+
case "WFED": {
|
|
406
|
+
const encoding2 = TextEncodingToken.get(uint8Array, 0);
|
|
407
|
+
uint8Array = uint8Array.subarray(1);
|
|
408
|
+
output = _FrameParser.readNullTerminatedString(uint8Array, encoding2).text;
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
case "MCDI": {
|
|
412
|
+
output = uint8Array.subarray(0, length);
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
// ID3v2 Chapters 1.0
|
|
416
|
+
// https://mutagen-specs.readthedocs.io/en/latest/id3/id3v2-chapters-1.0.html#chapter-frame
|
|
417
|
+
case "CHAP": {
|
|
418
|
+
debug("Reading CHAP");
|
|
419
|
+
fzero = findZero(uint8Array, defaultEnc);
|
|
420
|
+
const chapter = {
|
|
421
|
+
label: decodeString(uint8Array.subarray(0, fzero), defaultEnc),
|
|
422
|
+
info: ChapterInfo.get(uint8Array, fzero + 1),
|
|
423
|
+
frames: /* @__PURE__ */ new Map()
|
|
424
|
+
};
|
|
425
|
+
offset += fzero + 1 + ChapterInfo.len;
|
|
426
|
+
while (offset < length) {
|
|
427
|
+
const subFrame = readFrameHeader(uint8Array.subarray(offset), this.major, this.warningCollector);
|
|
428
|
+
const headerSize = getFrameHeaderLength(this.major);
|
|
429
|
+
offset += headerSize;
|
|
430
|
+
const subOutput = this.readData(uint8Array.subarray(offset, offset + subFrame.length), subFrame.id, includeCovers);
|
|
431
|
+
offset += subFrame.length;
|
|
432
|
+
chapter.frames.set(subFrame.id, subOutput);
|
|
433
|
+
}
|
|
434
|
+
output = chapter;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
// ID3v2 Chapters 1.0
|
|
438
|
+
// https://mutagen-specs.readthedocs.io/en/latest/id3/id3v2-chapters-1.0.html#table-of-contents-frame
|
|
439
|
+
case "CTOC": {
|
|
440
|
+
debug("Reading CTOC");
|
|
441
|
+
const idEnd = findZero(uint8Array, defaultEnc);
|
|
442
|
+
const label = decodeString(uint8Array.subarray(0, idEnd), defaultEnc);
|
|
443
|
+
offset = idEnd + 1;
|
|
444
|
+
const flags = uint8Array[offset++];
|
|
445
|
+
const topLevel = (flags & 2) !== 0;
|
|
446
|
+
const ordered = (flags & 1) !== 0;
|
|
447
|
+
const entryCount = uint8Array[offset++];
|
|
448
|
+
const childElementIds = [];
|
|
449
|
+
for (let i = 0; i < entryCount && offset < length; i++) {
|
|
450
|
+
const end = findZero(uint8Array.subarray(offset), defaultEnc);
|
|
451
|
+
const childId = decodeString(uint8Array.subarray(offset, offset + end), defaultEnc);
|
|
452
|
+
childElementIds.push(childId);
|
|
453
|
+
offset += end + 1;
|
|
454
|
+
}
|
|
455
|
+
const toc = {
|
|
456
|
+
label,
|
|
457
|
+
flags: { topLevel, ordered },
|
|
458
|
+
childElementIds,
|
|
459
|
+
frames: /* @__PURE__ */ new Map()
|
|
460
|
+
};
|
|
461
|
+
while (offset < length) {
|
|
462
|
+
const subFrame = readFrameHeader(uint8Array.subarray(offset), this.major, this.warningCollector);
|
|
463
|
+
const headerSize = getFrameHeaderLength(this.major);
|
|
464
|
+
offset += headerSize;
|
|
465
|
+
const subOutput = this.readData(uint8Array.subarray(offset, offset + subFrame.length), subFrame.id, includeCovers);
|
|
466
|
+
offset += subFrame.length;
|
|
467
|
+
toc.frames.set(subFrame.id, subOutput);
|
|
468
|
+
}
|
|
469
|
+
output = toc;
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
default:
|
|
473
|
+
debug(`Warning: unsupported id3v2-tag-type: ${type}`);
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
return output;
|
|
477
|
+
}
|
|
478
|
+
static readNullTerminatedString(uint8Array, encoding) {
|
|
479
|
+
const bomSize = encoding.bom ? 2 : 0;
|
|
480
|
+
const originalLen = uint8Array.length;
|
|
481
|
+
const valueArray = uint8Array.subarray(bomSize);
|
|
482
|
+
const zeroIndex = findZero(valueArray, encoding.encoding);
|
|
483
|
+
if (zeroIndex >= valueArray.length) {
|
|
484
|
+
return {
|
|
485
|
+
text: decodeString(valueArray, encoding.encoding),
|
|
486
|
+
len: originalLen
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
const txt = valueArray.subarray(0, zeroIndex);
|
|
490
|
+
return {
|
|
491
|
+
text: decodeString(txt, encoding.encoding),
|
|
492
|
+
len: bomSize + zeroIndex + _FrameParser.getNullTerminatorLength(encoding.encoding)
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
static fixPictureMimeType(pictureType) {
|
|
496
|
+
pictureType = pictureType.toLocaleLowerCase();
|
|
497
|
+
switch (pictureType) {
|
|
498
|
+
case "jpg":
|
|
499
|
+
return "image/jpeg";
|
|
500
|
+
case "png":
|
|
501
|
+
return "image/png";
|
|
502
|
+
}
|
|
503
|
+
return pictureType;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Converts TMCL (Musician credits list) or TIPL (Involved people list)
|
|
507
|
+
* @param entries
|
|
508
|
+
*/
|
|
509
|
+
static functionList(entries) {
|
|
510
|
+
const res = {};
|
|
511
|
+
for (let i = 0; i + 1 < entries.length; i += 2) {
|
|
512
|
+
const names = entries[i + 1].split(",");
|
|
513
|
+
res[entries[i]] = res[entries[i]] ? res[entries[i]].concat(names) : names;
|
|
514
|
+
}
|
|
515
|
+
return res;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* id3v2.4 defines that multiple T* values are separated by 0x00
|
|
519
|
+
* id3v2.3 defines that TCOM, TEXT, TOLY, TOPE & TPE1 values are separated by /
|
|
520
|
+
* @param tag - Tag name
|
|
521
|
+
* @param text - Concatenated tag value
|
|
522
|
+
* @returns Split tag value
|
|
523
|
+
*/
|
|
524
|
+
splitValue(tag, text) {
|
|
525
|
+
let values;
|
|
526
|
+
if (this.major < 4) {
|
|
527
|
+
values = text.split(/\x00/g);
|
|
528
|
+
if (values.length > 1) {
|
|
529
|
+
this.warningCollector.addWarning(`ID3v2.${this.major} ${tag} uses non standard null-separator.`);
|
|
530
|
+
} else {
|
|
531
|
+
values = text.split(/\//g);
|
|
532
|
+
}
|
|
533
|
+
} else {
|
|
534
|
+
values = text.split(/\x00/g);
|
|
535
|
+
}
|
|
536
|
+
return _FrameParser.trimArray(values);
|
|
537
|
+
}
|
|
538
|
+
static trimArray(values) {
|
|
539
|
+
return values.map((value) => _FrameParser.trimNullPadding(value).trim());
|
|
540
|
+
}
|
|
541
|
+
static trimNullPadding(value) {
|
|
542
|
+
let end = value.length;
|
|
543
|
+
while (end > 0 && value.charCodeAt(end - 1) === 0) {
|
|
544
|
+
end--;
|
|
545
|
+
}
|
|
546
|
+
return end === value.length ? value : value.slice(0, end);
|
|
547
|
+
}
|
|
548
|
+
static readIdentifierAndData(uint8Array, encoding) {
|
|
549
|
+
const idStr = _FrameParser.readNullTerminatedString(uint8Array, { encoding, bom: false });
|
|
550
|
+
return { id: idStr.text, data: uint8Array.subarray(idStr.len) };
|
|
551
|
+
}
|
|
552
|
+
static getNullTerminatorLength(enc) {
|
|
553
|
+
return enc.startsWith("utf-16") ? 2 : 1;
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
var Id3v2ContentError = class extends makeUnexpectedFileContentError("id3v2") {
|
|
557
|
+
};
|
|
558
|
+
function makeUnexpectedMajorVersionError2(majorVer) {
|
|
559
|
+
throw new Id3v2ContentError(`Unexpected majorVer: ${majorVer}`);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/id3v2/ID3v2Parser.js
|
|
563
|
+
var ID3v2Parser = class _ID3v2Parser {
|
|
564
|
+
constructor() {
|
|
565
|
+
this.tokenizer = void 0;
|
|
566
|
+
this.id3Header = void 0;
|
|
567
|
+
this.metadata = void 0;
|
|
568
|
+
this.headerType = void 0;
|
|
569
|
+
this.options = void 0;
|
|
570
|
+
}
|
|
571
|
+
static removeUnsyncBytes(buffer) {
|
|
572
|
+
let readI = 0;
|
|
573
|
+
let writeI = 0;
|
|
574
|
+
while (readI < buffer.length - 1) {
|
|
575
|
+
if (readI !== writeI) {
|
|
576
|
+
buffer[writeI] = buffer[readI];
|
|
577
|
+
}
|
|
578
|
+
readI += buffer[readI] === 255 && buffer[readI + 1] === 0 ? 2 : 1;
|
|
579
|
+
writeI++;
|
|
580
|
+
}
|
|
581
|
+
if (readI < buffer.length) {
|
|
582
|
+
buffer[writeI++] = buffer[readI];
|
|
583
|
+
}
|
|
584
|
+
return buffer.subarray(0, writeI);
|
|
585
|
+
}
|
|
586
|
+
static readFrameData(uint8Array, frameHeader, majorVer, includeCovers, warningCollector) {
|
|
587
|
+
const frameParser = new FrameParser(majorVer, warningCollector);
|
|
588
|
+
switch (majorVer) {
|
|
589
|
+
case 2:
|
|
590
|
+
return frameParser.readData(uint8Array, frameHeader.id, includeCovers);
|
|
591
|
+
case 3:
|
|
592
|
+
case 4:
|
|
593
|
+
if (frameHeader.flags?.format.unsynchronisation) {
|
|
594
|
+
uint8Array = _ID3v2Parser.removeUnsyncBytes(uint8Array);
|
|
595
|
+
}
|
|
596
|
+
if (frameHeader.flags?.format.data_length_indicator) {
|
|
597
|
+
uint8Array = uint8Array.subarray(4, uint8Array.length);
|
|
598
|
+
}
|
|
599
|
+
return frameParser.readData(uint8Array, frameHeader.id, includeCovers);
|
|
600
|
+
default:
|
|
601
|
+
throw makeUnexpectedMajorVersionError3(majorVer);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Create a combined tag key, of tag & description
|
|
606
|
+
* @param tag e.g.: COM
|
|
607
|
+
* @param description e.g. iTunPGAP
|
|
608
|
+
* @returns string e.g. COM:iTunPGAP
|
|
609
|
+
*/
|
|
610
|
+
static makeDescriptionTagName(tag, description) {
|
|
611
|
+
return tag + (description ? `:${description}` : "");
|
|
612
|
+
}
|
|
613
|
+
async parse(metadata, tokenizer, options) {
|
|
614
|
+
this.tokenizer = tokenizer;
|
|
615
|
+
this.metadata = metadata;
|
|
616
|
+
this.options = options;
|
|
617
|
+
const id3Header = await this.tokenizer.readToken(ID3v2Header);
|
|
618
|
+
if (id3Header.fileIdentifier !== "ID3") {
|
|
619
|
+
throw new Id3v2ContentError("expected ID3-header file-identifier 'ID3' was not found");
|
|
620
|
+
}
|
|
621
|
+
this.id3Header = id3Header;
|
|
622
|
+
this.headerType = `ID3v2.${id3Header.version.major}`;
|
|
623
|
+
await (id3Header.flags.isExtendedHeader ? this.parseExtendedHeader() : this.parseId3Data(id3Header.size));
|
|
624
|
+
const chapters = _ID3v2Parser.mapId3v2Chapters(this.metadata.native[this.headerType]);
|
|
625
|
+
this.metadata.setFormat("chapters", chapters);
|
|
626
|
+
}
|
|
627
|
+
async parseExtendedHeader() {
|
|
628
|
+
const extendedHeader = await this.tokenizer.readToken(ExtendedHeader);
|
|
629
|
+
const dataRemaining = extendedHeader.size - ExtendedHeader.len;
|
|
630
|
+
return dataRemaining > 0 ? this.parseExtendedHeaderData(dataRemaining, extendedHeader.size) : this.parseId3Data(this.id3Header.size - extendedHeader.size);
|
|
631
|
+
}
|
|
632
|
+
async parseExtendedHeaderData(dataRemaining, extendedHeaderSize) {
|
|
633
|
+
await this.tokenizer.ignore(dataRemaining);
|
|
634
|
+
return this.parseId3Data(this.id3Header.size - extendedHeaderSize);
|
|
635
|
+
}
|
|
636
|
+
async parseId3Data(dataLen) {
|
|
637
|
+
const uint8Array = await this.tokenizer.readToken(new Uint8ArrayType(dataLen));
|
|
638
|
+
for (const tag of this.parseMetadata(uint8Array)) {
|
|
639
|
+
switch (tag.id) {
|
|
640
|
+
case "TXXX":
|
|
641
|
+
if (tag.value) {
|
|
642
|
+
await this.handleTag(tag, tag.value.text, () => tag.value.description);
|
|
643
|
+
}
|
|
644
|
+
break;
|
|
645
|
+
default:
|
|
646
|
+
await (Array.isArray(tag.value) ? Promise.all(tag.value.map((value) => this.addTag(tag.id, value))) : this.addTag(tag.id, tag.value));
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
async handleTag(tag, values, descriptor, resolveValue = (value) => value) {
|
|
651
|
+
await Promise.all(values.map((value) => this.addTag(_ID3v2Parser.makeDescriptionTagName(tag.id, descriptor(value)), resolveValue(value))));
|
|
652
|
+
}
|
|
653
|
+
async addTag(id, value) {
|
|
654
|
+
await this.metadata.addTag(this.headerType, id, value);
|
|
655
|
+
}
|
|
656
|
+
parseMetadata(data) {
|
|
657
|
+
let offset = 0;
|
|
658
|
+
const tags = [];
|
|
659
|
+
while (true) {
|
|
660
|
+
if (offset === data.length)
|
|
661
|
+
break;
|
|
662
|
+
const frameHeaderLength = getFrameHeaderLength(this.id3Header.version.major);
|
|
663
|
+
if (offset + frameHeaderLength > data.length) {
|
|
664
|
+
this.metadata.addWarning("Illegal ID3v2 tag length");
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
const frameHeaderBytes = data.subarray(offset, offset + frameHeaderLength);
|
|
668
|
+
offset += frameHeaderLength;
|
|
669
|
+
const frameHeader = readFrameHeader(frameHeaderBytes, this.id3Header.version.major, this.metadata);
|
|
670
|
+
const frameDataBytes = data.subarray(offset, offset + frameHeader.length);
|
|
671
|
+
offset += frameHeader.length;
|
|
672
|
+
const values = _ID3v2Parser.readFrameData(frameDataBytes, frameHeader, this.id3Header.version.major, !this.options.skipCovers, this.metadata);
|
|
673
|
+
if (values) {
|
|
674
|
+
tags.push({ id: frameHeader.id, value: values });
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return tags;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Convert parsed ID3v2 chapter frames (CHAP / CTOC) to generic `format.chapters`.
|
|
681
|
+
*
|
|
682
|
+
* This function expects the `native` tags already to contain parsed `CHAP` and `CTOC` frame values,
|
|
683
|
+
* as produced by `FrameParser.readData`.
|
|
684
|
+
*/
|
|
685
|
+
static mapId3v2Chapters(id3Tags) {
|
|
686
|
+
if (!id3Tags)
|
|
687
|
+
return;
|
|
688
|
+
const chapFrames = id3Tags.filter((t) => t.id === "CHAP");
|
|
689
|
+
if (!chapFrames?.length)
|
|
690
|
+
return;
|
|
691
|
+
const tocFrames = id3Tags.filter((t) => t.id === "CTOC");
|
|
692
|
+
const topLevelToc = tocFrames?.find((t) => t.value.flags?.topLevel);
|
|
693
|
+
const chapterById = /* @__PURE__ */ new Map();
|
|
694
|
+
for (const chap of chapFrames) {
|
|
695
|
+
chapterById.set(chap.value.label, chap.value);
|
|
696
|
+
}
|
|
697
|
+
const orderedIds = topLevelToc?.value.childElementIds;
|
|
698
|
+
const chapters = [];
|
|
699
|
+
const source = orderedIds ?? [...chapterById.keys()];
|
|
700
|
+
for (const id of source) {
|
|
701
|
+
const chap = chapterById.get(id);
|
|
702
|
+
if (!chap)
|
|
703
|
+
continue;
|
|
704
|
+
const frames = chap.frames;
|
|
705
|
+
const title = frames.get("TIT2");
|
|
706
|
+
if (!title)
|
|
707
|
+
continue;
|
|
708
|
+
chapters.push({
|
|
709
|
+
id,
|
|
710
|
+
title,
|
|
711
|
+
url: frames.get("WXXX"),
|
|
712
|
+
start: chap.info.startTime / 1e3,
|
|
713
|
+
end: chap.info.endTime / 1e3,
|
|
714
|
+
image: frames.get("APIC")
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
if (!orderedIds) {
|
|
718
|
+
chapters.sort((a, b) => a.start - b.start);
|
|
719
|
+
}
|
|
720
|
+
return chapters.length ? chapters : void 0;
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
function makeUnexpectedMajorVersionError3(majorVer) {
|
|
724
|
+
throw new Id3v2ContentError(`Unexpected majorVer: ${majorVer}`);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
export {
|
|
728
|
+
ID3v2Parser
|
|
729
|
+
};
|