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,4161 @@
|
|
|
1
|
+
import "./chunk-6OKLAJRQ.js";
|
|
2
|
+
import {
|
|
3
|
+
TrackType,
|
|
4
|
+
TrackTypeValueToKeyMap
|
|
5
|
+
} from "./chunk-M54HVABG.js";
|
|
6
|
+
import {
|
|
7
|
+
hasID3v1Header
|
|
8
|
+
} from "./chunk-2B4QMSZW.js";
|
|
9
|
+
import {
|
|
10
|
+
APEv2Parser
|
|
11
|
+
} from "./chunk-YIHDW7JC.js";
|
|
12
|
+
import {
|
|
13
|
+
EndOfStreamError,
|
|
14
|
+
fromBlob,
|
|
15
|
+
fromBuffer,
|
|
16
|
+
fromFile,
|
|
17
|
+
fromStream,
|
|
18
|
+
fromWebStream
|
|
19
|
+
} from "./chunk-HNLU36CC.js";
|
|
20
|
+
import {
|
|
21
|
+
LyricsContentType,
|
|
22
|
+
TimestampFormat
|
|
23
|
+
} from "./chunk-LREP5CZP.js";
|
|
24
|
+
import {
|
|
25
|
+
decodeString,
|
|
26
|
+
getUintBE,
|
|
27
|
+
toRatio
|
|
28
|
+
} from "./chunk-GD35BJSH.js";
|
|
29
|
+
import {
|
|
30
|
+
CouldNotDetermineFileTypeError,
|
|
31
|
+
FieldDecodingError,
|
|
32
|
+
INT32_BE,
|
|
33
|
+
InternalParserError,
|
|
34
|
+
StringType,
|
|
35
|
+
UINT16_BE,
|
|
36
|
+
UINT16_LE,
|
|
37
|
+
UINT32_BE,
|
|
38
|
+
UINT32_LE,
|
|
39
|
+
UINT64_LE,
|
|
40
|
+
UINT8,
|
|
41
|
+
UnsupportedFileTypeError,
|
|
42
|
+
makeParseError,
|
|
43
|
+
makeUnexpectedFileContentError,
|
|
44
|
+
require_src,
|
|
45
|
+
textDecode
|
|
46
|
+
} from "./chunk-VGOIHW7D.js";
|
|
47
|
+
import {
|
|
48
|
+
__commonJS,
|
|
49
|
+
__toESM
|
|
50
|
+
} from "./chunk-4VNS5WPM.js";
|
|
51
|
+
|
|
52
|
+
// ../../node_modules/.pnpm/content-type@1.0.5/node_modules/content-type/index.js
|
|
53
|
+
var require_content_type = __commonJS({
|
|
54
|
+
"../../node_modules/.pnpm/content-type@1.0.5/node_modules/content-type/index.js"(exports) {
|
|
55
|
+
"use strict";
|
|
56
|
+
var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g;
|
|
57
|
+
var TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/;
|
|
58
|
+
var TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
59
|
+
var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g;
|
|
60
|
+
var QUOTE_REGEXP = /([\\"])/g;
|
|
61
|
+
var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
62
|
+
exports.format = format;
|
|
63
|
+
exports.parse = parse;
|
|
64
|
+
function format(obj) {
|
|
65
|
+
if (!obj || typeof obj !== "object") {
|
|
66
|
+
throw new TypeError("argument obj is required");
|
|
67
|
+
}
|
|
68
|
+
var parameters = obj.parameters;
|
|
69
|
+
var type = obj.type;
|
|
70
|
+
if (!type || !TYPE_REGEXP.test(type)) {
|
|
71
|
+
throw new TypeError("invalid type");
|
|
72
|
+
}
|
|
73
|
+
var string = type;
|
|
74
|
+
if (parameters && typeof parameters === "object") {
|
|
75
|
+
var param;
|
|
76
|
+
var params = Object.keys(parameters).sort();
|
|
77
|
+
for (var i = 0; i < params.length; i++) {
|
|
78
|
+
param = params[i];
|
|
79
|
+
if (!TOKEN_REGEXP.test(param)) {
|
|
80
|
+
throw new TypeError("invalid parameter name");
|
|
81
|
+
}
|
|
82
|
+
string += "; " + param + "=" + qstring(parameters[param]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return string;
|
|
86
|
+
}
|
|
87
|
+
function parse(string) {
|
|
88
|
+
if (!string) {
|
|
89
|
+
throw new TypeError("argument string is required");
|
|
90
|
+
}
|
|
91
|
+
var header = typeof string === "object" ? getcontenttype(string) : string;
|
|
92
|
+
if (typeof header !== "string") {
|
|
93
|
+
throw new TypeError("argument string is required to be a string");
|
|
94
|
+
}
|
|
95
|
+
var index = header.indexOf(";");
|
|
96
|
+
var type = index !== -1 ? header.slice(0, index).trim() : header.trim();
|
|
97
|
+
if (!TYPE_REGEXP.test(type)) {
|
|
98
|
+
throw new TypeError("invalid media type");
|
|
99
|
+
}
|
|
100
|
+
var obj = new ContentType2(type.toLowerCase());
|
|
101
|
+
if (index !== -1) {
|
|
102
|
+
var key;
|
|
103
|
+
var match;
|
|
104
|
+
var value;
|
|
105
|
+
PARAM_REGEXP.lastIndex = index;
|
|
106
|
+
while (match = PARAM_REGEXP.exec(header)) {
|
|
107
|
+
if (match.index !== index) {
|
|
108
|
+
throw new TypeError("invalid parameter format");
|
|
109
|
+
}
|
|
110
|
+
index += match[0].length;
|
|
111
|
+
key = match[1].toLowerCase();
|
|
112
|
+
value = match[2];
|
|
113
|
+
if (value.charCodeAt(0) === 34) {
|
|
114
|
+
value = value.slice(1, -1);
|
|
115
|
+
if (value.indexOf("\\") !== -1) {
|
|
116
|
+
value = value.replace(QESC_REGEXP, "$1");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
obj.parameters[key] = value;
|
|
120
|
+
}
|
|
121
|
+
if (index !== header.length) {
|
|
122
|
+
throw new TypeError("invalid parameter format");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return obj;
|
|
126
|
+
}
|
|
127
|
+
function getcontenttype(obj) {
|
|
128
|
+
var header;
|
|
129
|
+
if (typeof obj.getHeader === "function") {
|
|
130
|
+
header = obj.getHeader("content-type");
|
|
131
|
+
} else if (typeof obj.headers === "object") {
|
|
132
|
+
header = obj.headers && obj.headers["content-type"];
|
|
133
|
+
}
|
|
134
|
+
if (typeof header !== "string") {
|
|
135
|
+
throw new TypeError("content-type header is missing from object");
|
|
136
|
+
}
|
|
137
|
+
return header;
|
|
138
|
+
}
|
|
139
|
+
function qstring(val) {
|
|
140
|
+
var str = String(val);
|
|
141
|
+
if (TOKEN_REGEXP.test(str)) {
|
|
142
|
+
return str;
|
|
143
|
+
}
|
|
144
|
+
if (str.length > 0 && !TEXT_REGEXP.test(str)) {
|
|
145
|
+
throw new TypeError("invalid parameter value");
|
|
146
|
+
}
|
|
147
|
+
return '"' + str.replace(QUOTE_REGEXP, "\\$1") + '"';
|
|
148
|
+
}
|
|
149
|
+
function ContentType2(type) {
|
|
150
|
+
this.parameters = /* @__PURE__ */ Object.create(null);
|
|
151
|
+
this.type = type;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// ../../node_modules/.pnpm/media-typer@1.1.0/node_modules/media-typer/index.js
|
|
157
|
+
var require_media_typer = __commonJS({
|
|
158
|
+
"../../node_modules/.pnpm/media-typer@1.1.0/node_modules/media-typer/index.js"(exports) {
|
|
159
|
+
"use strict";
|
|
160
|
+
var SUBTYPE_NAME_REGEXP = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.-]{0,126}$/;
|
|
161
|
+
var TYPE_NAME_REGEXP = /^[A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126}$/;
|
|
162
|
+
var TYPE_REGEXP = /^ *([A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126})\/([A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}) *$/;
|
|
163
|
+
exports.format = format;
|
|
164
|
+
exports.parse = parse;
|
|
165
|
+
exports.test = test;
|
|
166
|
+
function format(obj) {
|
|
167
|
+
if (!obj || typeof obj !== "object") {
|
|
168
|
+
throw new TypeError("argument obj is required");
|
|
169
|
+
}
|
|
170
|
+
var subtype = obj.subtype;
|
|
171
|
+
var suffix = obj.suffix;
|
|
172
|
+
var type = obj.type;
|
|
173
|
+
if (!type || !TYPE_NAME_REGEXP.test(type)) {
|
|
174
|
+
throw new TypeError("invalid type");
|
|
175
|
+
}
|
|
176
|
+
if (!subtype || !SUBTYPE_NAME_REGEXP.test(subtype)) {
|
|
177
|
+
throw new TypeError("invalid subtype");
|
|
178
|
+
}
|
|
179
|
+
var string = type + "/" + subtype;
|
|
180
|
+
if (suffix) {
|
|
181
|
+
if (!TYPE_NAME_REGEXP.test(suffix)) {
|
|
182
|
+
throw new TypeError("invalid suffix");
|
|
183
|
+
}
|
|
184
|
+
string += "+" + suffix;
|
|
185
|
+
}
|
|
186
|
+
return string;
|
|
187
|
+
}
|
|
188
|
+
function test(string) {
|
|
189
|
+
if (!string) {
|
|
190
|
+
throw new TypeError("argument string is required");
|
|
191
|
+
}
|
|
192
|
+
if (typeof string !== "string") {
|
|
193
|
+
throw new TypeError("argument string is required to be a string");
|
|
194
|
+
}
|
|
195
|
+
return TYPE_REGEXP.test(string.toLowerCase());
|
|
196
|
+
}
|
|
197
|
+
function parse(string) {
|
|
198
|
+
if (!string) {
|
|
199
|
+
throw new TypeError("argument string is required");
|
|
200
|
+
}
|
|
201
|
+
if (typeof string !== "string") {
|
|
202
|
+
throw new TypeError("argument string is required to be a string");
|
|
203
|
+
}
|
|
204
|
+
var match = TYPE_REGEXP.exec(string.toLowerCase());
|
|
205
|
+
if (!match) {
|
|
206
|
+
throw new TypeError("invalid media type");
|
|
207
|
+
}
|
|
208
|
+
var type = match[1];
|
|
209
|
+
var subtype = match[2];
|
|
210
|
+
var suffix;
|
|
211
|
+
var index = subtype.lastIndexOf("+");
|
|
212
|
+
if (index !== -1) {
|
|
213
|
+
suffix = subtype.substr(index + 1);
|
|
214
|
+
subtype = subtype.substr(0, index);
|
|
215
|
+
}
|
|
216
|
+
return new MediaType(type, subtype, suffix);
|
|
217
|
+
}
|
|
218
|
+
function MediaType(type, subtype, suffix) {
|
|
219
|
+
this.type = type;
|
|
220
|
+
this.subtype = subtype;
|
|
221
|
+
this.suffix = suffix;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/index.js
|
|
227
|
+
var import_debug4 = __toESM(require_src(), 1);
|
|
228
|
+
|
|
229
|
+
// ../../node_modules/.pnpm/file-type@21.3.0/node_modules/file-type/index.js
|
|
230
|
+
import { ReadableStream as WebReadableStream } from "stream/web";
|
|
231
|
+
import { pipeline, PassThrough, Readable } from "stream";
|
|
232
|
+
|
|
233
|
+
// ../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/ZipHandler.js
|
|
234
|
+
var import_debug = __toESM(require_src(), 1);
|
|
235
|
+
|
|
236
|
+
// ../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/ZipToken.js
|
|
237
|
+
var Signature = {
|
|
238
|
+
LocalFileHeader: 67324752,
|
|
239
|
+
DataDescriptor: 134695760,
|
|
240
|
+
CentralFileHeader: 33639248,
|
|
241
|
+
EndOfCentralDirectory: 101010256
|
|
242
|
+
};
|
|
243
|
+
var DataDescriptor = {
|
|
244
|
+
get(array) {
|
|
245
|
+
return {
|
|
246
|
+
signature: UINT32_LE.get(array, 0),
|
|
247
|
+
compressedSize: UINT32_LE.get(array, 8),
|
|
248
|
+
uncompressedSize: UINT32_LE.get(array, 12)
|
|
249
|
+
};
|
|
250
|
+
},
|
|
251
|
+
len: 16
|
|
252
|
+
};
|
|
253
|
+
var LocalFileHeaderToken = {
|
|
254
|
+
get(array) {
|
|
255
|
+
const flags = UINT16_LE.get(array, 6);
|
|
256
|
+
return {
|
|
257
|
+
signature: UINT32_LE.get(array, 0),
|
|
258
|
+
minVersion: UINT16_LE.get(array, 4),
|
|
259
|
+
dataDescriptor: !!(flags & 8),
|
|
260
|
+
compressedMethod: UINT16_LE.get(array, 8),
|
|
261
|
+
compressedSize: UINT32_LE.get(array, 18),
|
|
262
|
+
uncompressedSize: UINT32_LE.get(array, 22),
|
|
263
|
+
filenameLength: UINT16_LE.get(array, 26),
|
|
264
|
+
extraFieldLength: UINT16_LE.get(array, 28),
|
|
265
|
+
filename: null
|
|
266
|
+
};
|
|
267
|
+
},
|
|
268
|
+
len: 30
|
|
269
|
+
};
|
|
270
|
+
var EndOfCentralDirectoryRecordToken = {
|
|
271
|
+
get(array) {
|
|
272
|
+
return {
|
|
273
|
+
signature: UINT32_LE.get(array, 0),
|
|
274
|
+
nrOfThisDisk: UINT16_LE.get(array, 4),
|
|
275
|
+
nrOfThisDiskWithTheStart: UINT16_LE.get(array, 6),
|
|
276
|
+
nrOfEntriesOnThisDisk: UINT16_LE.get(array, 8),
|
|
277
|
+
nrOfEntriesOfSize: UINT16_LE.get(array, 10),
|
|
278
|
+
sizeOfCd: UINT32_LE.get(array, 12),
|
|
279
|
+
offsetOfStartOfCd: UINT32_LE.get(array, 16),
|
|
280
|
+
zipFileCommentLength: UINT16_LE.get(array, 20)
|
|
281
|
+
};
|
|
282
|
+
},
|
|
283
|
+
len: 22
|
|
284
|
+
};
|
|
285
|
+
var FileHeader = {
|
|
286
|
+
get(array) {
|
|
287
|
+
const flags = UINT16_LE.get(array, 8);
|
|
288
|
+
return {
|
|
289
|
+
signature: UINT32_LE.get(array, 0),
|
|
290
|
+
minVersion: UINT16_LE.get(array, 6),
|
|
291
|
+
dataDescriptor: !!(flags & 8),
|
|
292
|
+
compressedMethod: UINT16_LE.get(array, 10),
|
|
293
|
+
compressedSize: UINT32_LE.get(array, 20),
|
|
294
|
+
uncompressedSize: UINT32_LE.get(array, 24),
|
|
295
|
+
filenameLength: UINT16_LE.get(array, 28),
|
|
296
|
+
extraFieldLength: UINT16_LE.get(array, 30),
|
|
297
|
+
fileCommentLength: UINT16_LE.get(array, 32),
|
|
298
|
+
relativeOffsetOfLocalHeader: UINT32_LE.get(array, 42),
|
|
299
|
+
filename: null
|
|
300
|
+
};
|
|
301
|
+
},
|
|
302
|
+
len: 46
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// ../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/ZipHandler.js
|
|
306
|
+
function signatureToArray(signature) {
|
|
307
|
+
const signatureBytes = new Uint8Array(UINT32_LE.len);
|
|
308
|
+
UINT32_LE.put(signatureBytes, 0, signature);
|
|
309
|
+
return signatureBytes;
|
|
310
|
+
}
|
|
311
|
+
var debug = (0, import_debug.default)("tokenizer:inflate");
|
|
312
|
+
var syncBufferSize = 256 * 1024;
|
|
313
|
+
var ddSignatureArray = signatureToArray(Signature.DataDescriptor);
|
|
314
|
+
var eocdSignatureBytes = signatureToArray(Signature.EndOfCentralDirectory);
|
|
315
|
+
var ZipHandler = class _ZipHandler {
|
|
316
|
+
constructor(tokenizer) {
|
|
317
|
+
this.tokenizer = tokenizer;
|
|
318
|
+
this.syncBuffer = new Uint8Array(syncBufferSize);
|
|
319
|
+
}
|
|
320
|
+
async isZip() {
|
|
321
|
+
return await this.peekSignature() === Signature.LocalFileHeader;
|
|
322
|
+
}
|
|
323
|
+
peekSignature() {
|
|
324
|
+
return this.tokenizer.peekToken(UINT32_LE);
|
|
325
|
+
}
|
|
326
|
+
async findEndOfCentralDirectoryLocator() {
|
|
327
|
+
const randomReadTokenizer = this.tokenizer;
|
|
328
|
+
const chunkLength = Math.min(16 * 1024, randomReadTokenizer.fileInfo.size);
|
|
329
|
+
const buffer = this.syncBuffer.subarray(0, chunkLength);
|
|
330
|
+
await this.tokenizer.readBuffer(buffer, { position: randomReadTokenizer.fileInfo.size - chunkLength });
|
|
331
|
+
for (let i = buffer.length - 4; i >= 0; i--) {
|
|
332
|
+
if (buffer[i] === eocdSignatureBytes[0] && buffer[i + 1] === eocdSignatureBytes[1] && buffer[i + 2] === eocdSignatureBytes[2] && buffer[i + 3] === eocdSignatureBytes[3]) {
|
|
333
|
+
return randomReadTokenizer.fileInfo.size - chunkLength + i;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return -1;
|
|
337
|
+
}
|
|
338
|
+
async readCentralDirectory() {
|
|
339
|
+
if (!this.tokenizer.supportsRandomAccess()) {
|
|
340
|
+
debug("Cannot reading central-directory without random-read support");
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
debug("Reading central-directory...");
|
|
344
|
+
const pos = this.tokenizer.position;
|
|
345
|
+
const offset = await this.findEndOfCentralDirectoryLocator();
|
|
346
|
+
if (offset > 0) {
|
|
347
|
+
debug("Central-directory 32-bit signature found");
|
|
348
|
+
const eocdHeader = await this.tokenizer.readToken(EndOfCentralDirectoryRecordToken, offset);
|
|
349
|
+
const files = [];
|
|
350
|
+
this.tokenizer.setPosition(eocdHeader.offsetOfStartOfCd);
|
|
351
|
+
for (let n = 0; n < eocdHeader.nrOfEntriesOfSize; ++n) {
|
|
352
|
+
const entry = await this.tokenizer.readToken(FileHeader);
|
|
353
|
+
if (entry.signature !== Signature.CentralFileHeader) {
|
|
354
|
+
throw new Error("Expected Central-File-Header signature");
|
|
355
|
+
}
|
|
356
|
+
entry.filename = await this.tokenizer.readToken(new StringType(entry.filenameLength, "utf-8"));
|
|
357
|
+
await this.tokenizer.ignore(entry.extraFieldLength);
|
|
358
|
+
await this.tokenizer.ignore(entry.fileCommentLength);
|
|
359
|
+
files.push(entry);
|
|
360
|
+
debug(`Add central-directory file-entry: n=${n + 1}/${files.length}: filename=${files[n].filename}`);
|
|
361
|
+
}
|
|
362
|
+
this.tokenizer.setPosition(pos);
|
|
363
|
+
return files;
|
|
364
|
+
}
|
|
365
|
+
this.tokenizer.setPosition(pos);
|
|
366
|
+
}
|
|
367
|
+
async unzip(fileCb) {
|
|
368
|
+
const entries = await this.readCentralDirectory();
|
|
369
|
+
if (entries) {
|
|
370
|
+
return this.iterateOverCentralDirectory(entries, fileCb);
|
|
371
|
+
}
|
|
372
|
+
let stop = false;
|
|
373
|
+
do {
|
|
374
|
+
const zipHeader = await this.readLocalFileHeader();
|
|
375
|
+
if (!zipHeader)
|
|
376
|
+
break;
|
|
377
|
+
const next = fileCb(zipHeader);
|
|
378
|
+
stop = !!next.stop;
|
|
379
|
+
let fileData;
|
|
380
|
+
await this.tokenizer.ignore(zipHeader.extraFieldLength);
|
|
381
|
+
if (zipHeader.dataDescriptor && zipHeader.compressedSize === 0) {
|
|
382
|
+
const chunks = [];
|
|
383
|
+
let len = syncBufferSize;
|
|
384
|
+
debug("Compressed-file-size unknown, scanning for next data-descriptor-signature....");
|
|
385
|
+
let nextHeaderIndex = -1;
|
|
386
|
+
while (nextHeaderIndex < 0 && len === syncBufferSize) {
|
|
387
|
+
len = await this.tokenizer.peekBuffer(this.syncBuffer, { mayBeLess: true });
|
|
388
|
+
nextHeaderIndex = indexOf(this.syncBuffer.subarray(0, len), ddSignatureArray);
|
|
389
|
+
const size = nextHeaderIndex >= 0 ? nextHeaderIndex : len;
|
|
390
|
+
if (next.handler) {
|
|
391
|
+
const data = new Uint8Array(size);
|
|
392
|
+
await this.tokenizer.readBuffer(data);
|
|
393
|
+
chunks.push(data);
|
|
394
|
+
} else {
|
|
395
|
+
await this.tokenizer.ignore(size);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
debug(`Found data-descriptor-signature at pos=${this.tokenizer.position}`);
|
|
399
|
+
if (next.handler) {
|
|
400
|
+
await this.inflate(zipHeader, mergeArrays(chunks), next.handler);
|
|
401
|
+
}
|
|
402
|
+
} else {
|
|
403
|
+
if (next.handler) {
|
|
404
|
+
debug(`Reading compressed-file-data: ${zipHeader.compressedSize} bytes`);
|
|
405
|
+
fileData = new Uint8Array(zipHeader.compressedSize);
|
|
406
|
+
await this.tokenizer.readBuffer(fileData);
|
|
407
|
+
await this.inflate(zipHeader, fileData, next.handler);
|
|
408
|
+
} else {
|
|
409
|
+
debug(`Ignoring compressed-file-data: ${zipHeader.compressedSize} bytes`);
|
|
410
|
+
await this.tokenizer.ignore(zipHeader.compressedSize);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
debug(`Reading data-descriptor at pos=${this.tokenizer.position}`);
|
|
414
|
+
if (zipHeader.dataDescriptor) {
|
|
415
|
+
const dataDescriptor = await this.tokenizer.readToken(DataDescriptor);
|
|
416
|
+
if (dataDescriptor.signature !== 134695760) {
|
|
417
|
+
throw new Error(`Expected data-descriptor-signature at position ${this.tokenizer.position - DataDescriptor.len}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
} while (!stop);
|
|
421
|
+
}
|
|
422
|
+
async iterateOverCentralDirectory(entries, fileCb) {
|
|
423
|
+
for (const fileHeader of entries) {
|
|
424
|
+
const next = fileCb(fileHeader);
|
|
425
|
+
if (next.handler) {
|
|
426
|
+
this.tokenizer.setPosition(fileHeader.relativeOffsetOfLocalHeader);
|
|
427
|
+
const zipHeader = await this.readLocalFileHeader();
|
|
428
|
+
if (zipHeader) {
|
|
429
|
+
await this.tokenizer.ignore(zipHeader.extraFieldLength);
|
|
430
|
+
const fileData = new Uint8Array(fileHeader.compressedSize);
|
|
431
|
+
await this.tokenizer.readBuffer(fileData);
|
|
432
|
+
await this.inflate(zipHeader, fileData, next.handler);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (next.stop)
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async inflate(zipHeader, fileData, cb) {
|
|
440
|
+
if (zipHeader.compressedMethod === 0) {
|
|
441
|
+
return cb(fileData);
|
|
442
|
+
}
|
|
443
|
+
if (zipHeader.compressedMethod !== 8) {
|
|
444
|
+
throw new Error(`Unsupported ZIP compression method: ${zipHeader.compressedMethod}`);
|
|
445
|
+
}
|
|
446
|
+
debug(`Decompress filename=${zipHeader.filename}, compressed-size=${fileData.length}`);
|
|
447
|
+
const uncompressedData = await _ZipHandler.decompressDeflateRaw(fileData);
|
|
448
|
+
return cb(uncompressedData);
|
|
449
|
+
}
|
|
450
|
+
static async decompressDeflateRaw(data) {
|
|
451
|
+
const input = new ReadableStream({
|
|
452
|
+
start(controller) {
|
|
453
|
+
controller.enqueue(data);
|
|
454
|
+
controller.close();
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
const ds = new DecompressionStream("deflate-raw");
|
|
458
|
+
const output = input.pipeThrough(ds);
|
|
459
|
+
try {
|
|
460
|
+
const response = new Response(output);
|
|
461
|
+
const buffer = await response.arrayBuffer();
|
|
462
|
+
return new Uint8Array(buffer);
|
|
463
|
+
} catch (err) {
|
|
464
|
+
const message = err instanceof Error ? `Failed to deflate ZIP entry: ${err.message}` : "Unknown decompression error in ZIP entry";
|
|
465
|
+
throw new TypeError(message);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async readLocalFileHeader() {
|
|
469
|
+
const signature = await this.tokenizer.peekToken(UINT32_LE);
|
|
470
|
+
if (signature === Signature.LocalFileHeader) {
|
|
471
|
+
const header = await this.tokenizer.readToken(LocalFileHeaderToken);
|
|
472
|
+
header.filename = await this.tokenizer.readToken(new StringType(header.filenameLength, "utf-8"));
|
|
473
|
+
return header;
|
|
474
|
+
}
|
|
475
|
+
if (signature === Signature.CentralFileHeader) {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
if (signature === 3759263696) {
|
|
479
|
+
throw new Error("Encrypted ZIP");
|
|
480
|
+
}
|
|
481
|
+
throw new Error("Unexpected signature");
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
function indexOf(buffer, portion) {
|
|
485
|
+
const bufferLength = buffer.length;
|
|
486
|
+
const portionLength = portion.length;
|
|
487
|
+
if (portionLength > bufferLength)
|
|
488
|
+
return -1;
|
|
489
|
+
for (let i = 0; i <= bufferLength - portionLength; i++) {
|
|
490
|
+
let found = true;
|
|
491
|
+
for (let j = 0; j < portionLength; j++) {
|
|
492
|
+
if (buffer[i + j] !== portion[j]) {
|
|
493
|
+
found = false;
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (found) {
|
|
498
|
+
return i;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return -1;
|
|
502
|
+
}
|
|
503
|
+
function mergeArrays(chunks) {
|
|
504
|
+
const totalLength = chunks.reduce((acc, curr) => acc + curr.length, 0);
|
|
505
|
+
const mergedArray = new Uint8Array(totalLength);
|
|
506
|
+
let offset = 0;
|
|
507
|
+
for (const chunk of chunks) {
|
|
508
|
+
mergedArray.set(chunk, offset);
|
|
509
|
+
offset += chunk.length;
|
|
510
|
+
}
|
|
511
|
+
return mergedArray;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// ../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/GzipHandler.js
|
|
515
|
+
var GzipHandler = class {
|
|
516
|
+
constructor(tokenizer) {
|
|
517
|
+
this.tokenizer = tokenizer;
|
|
518
|
+
}
|
|
519
|
+
inflate() {
|
|
520
|
+
const tokenizer = this.tokenizer;
|
|
521
|
+
return new ReadableStream({
|
|
522
|
+
async pull(controller) {
|
|
523
|
+
const buffer = new Uint8Array(1024);
|
|
524
|
+
const size = await tokenizer.readBuffer(buffer, { mayBeLess: true });
|
|
525
|
+
if (size === 0) {
|
|
526
|
+
controller.close();
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
controller.enqueue(buffer.subarray(0, size));
|
|
530
|
+
}
|
|
531
|
+
}).pipeThrough(new DecompressionStream("gzip"));
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
// ../../node_modules/.pnpm/file-type@21.3.0/node_modules/file-type/util.js
|
|
536
|
+
function stringToBytes(string, encoding) {
|
|
537
|
+
if (encoding === "utf-16le") {
|
|
538
|
+
const bytes = [];
|
|
539
|
+
for (let index = 0; index < string.length; index++) {
|
|
540
|
+
const code = string.charCodeAt(index);
|
|
541
|
+
bytes.push(code & 255, code >> 8 & 255);
|
|
542
|
+
}
|
|
543
|
+
return bytes;
|
|
544
|
+
}
|
|
545
|
+
if (encoding === "utf-16be") {
|
|
546
|
+
const bytes = [];
|
|
547
|
+
for (let index = 0; index < string.length; index++) {
|
|
548
|
+
const code = string.charCodeAt(index);
|
|
549
|
+
bytes.push(code >> 8 & 255, code & 255);
|
|
550
|
+
}
|
|
551
|
+
return bytes;
|
|
552
|
+
}
|
|
553
|
+
return [...string].map((character) => character.charCodeAt(0));
|
|
554
|
+
}
|
|
555
|
+
function tarHeaderChecksumMatches(arrayBuffer, offset = 0) {
|
|
556
|
+
const readSum = Number.parseInt(new StringType(6).get(arrayBuffer, 148).replace(/\0.*$/, "").trim(), 8);
|
|
557
|
+
if (Number.isNaN(readSum)) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
let sum = 8 * 32;
|
|
561
|
+
for (let index = offset; index < offset + 148; index++) {
|
|
562
|
+
sum += arrayBuffer[index];
|
|
563
|
+
}
|
|
564
|
+
for (let index = offset + 156; index < offset + 512; index++) {
|
|
565
|
+
sum += arrayBuffer[index];
|
|
566
|
+
}
|
|
567
|
+
return readSum === sum;
|
|
568
|
+
}
|
|
569
|
+
var uint32SyncSafeToken = {
|
|
570
|
+
get: (buffer, offset) => buffer[offset + 3] & 127 | buffer[offset + 2] << 7 | buffer[offset + 1] << 14 | buffer[offset] << 21,
|
|
571
|
+
len: 4
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
// ../../node_modules/.pnpm/file-type@21.3.0/node_modules/file-type/supported.js
|
|
575
|
+
var extensions = [
|
|
576
|
+
"jpg",
|
|
577
|
+
"png",
|
|
578
|
+
"apng",
|
|
579
|
+
"gif",
|
|
580
|
+
"webp",
|
|
581
|
+
"flif",
|
|
582
|
+
"xcf",
|
|
583
|
+
"cr2",
|
|
584
|
+
"cr3",
|
|
585
|
+
"orf",
|
|
586
|
+
"arw",
|
|
587
|
+
"dng",
|
|
588
|
+
"nef",
|
|
589
|
+
"rw2",
|
|
590
|
+
"raf",
|
|
591
|
+
"tif",
|
|
592
|
+
"bmp",
|
|
593
|
+
"icns",
|
|
594
|
+
"jxr",
|
|
595
|
+
"psd",
|
|
596
|
+
"indd",
|
|
597
|
+
"zip",
|
|
598
|
+
"tar",
|
|
599
|
+
"rar",
|
|
600
|
+
"gz",
|
|
601
|
+
"bz2",
|
|
602
|
+
"7z",
|
|
603
|
+
"dmg",
|
|
604
|
+
"mp4",
|
|
605
|
+
"mid",
|
|
606
|
+
"mkv",
|
|
607
|
+
"webm",
|
|
608
|
+
"mov",
|
|
609
|
+
"avi",
|
|
610
|
+
"mpg",
|
|
611
|
+
"mp2",
|
|
612
|
+
"mp3",
|
|
613
|
+
"m4a",
|
|
614
|
+
"oga",
|
|
615
|
+
"ogg",
|
|
616
|
+
"ogv",
|
|
617
|
+
"opus",
|
|
618
|
+
"flac",
|
|
619
|
+
"wav",
|
|
620
|
+
"spx",
|
|
621
|
+
"amr",
|
|
622
|
+
"pdf",
|
|
623
|
+
"epub",
|
|
624
|
+
"elf",
|
|
625
|
+
"macho",
|
|
626
|
+
"exe",
|
|
627
|
+
"swf",
|
|
628
|
+
"rtf",
|
|
629
|
+
"wasm",
|
|
630
|
+
"woff",
|
|
631
|
+
"woff2",
|
|
632
|
+
"eot",
|
|
633
|
+
"ttf",
|
|
634
|
+
"otf",
|
|
635
|
+
"ttc",
|
|
636
|
+
"ico",
|
|
637
|
+
"flv",
|
|
638
|
+
"ps",
|
|
639
|
+
"xz",
|
|
640
|
+
"sqlite",
|
|
641
|
+
"nes",
|
|
642
|
+
"crx",
|
|
643
|
+
"xpi",
|
|
644
|
+
"cab",
|
|
645
|
+
"deb",
|
|
646
|
+
"ar",
|
|
647
|
+
"rpm",
|
|
648
|
+
"Z",
|
|
649
|
+
"lz",
|
|
650
|
+
"cfb",
|
|
651
|
+
"mxf",
|
|
652
|
+
"mts",
|
|
653
|
+
"blend",
|
|
654
|
+
"bpg",
|
|
655
|
+
"docx",
|
|
656
|
+
"pptx",
|
|
657
|
+
"xlsx",
|
|
658
|
+
"3gp",
|
|
659
|
+
"3g2",
|
|
660
|
+
"j2c",
|
|
661
|
+
"jp2",
|
|
662
|
+
"jpm",
|
|
663
|
+
"jpx",
|
|
664
|
+
"mj2",
|
|
665
|
+
"aif",
|
|
666
|
+
"qcp",
|
|
667
|
+
"odt",
|
|
668
|
+
"ods",
|
|
669
|
+
"odp",
|
|
670
|
+
"xml",
|
|
671
|
+
"mobi",
|
|
672
|
+
"heic",
|
|
673
|
+
"cur",
|
|
674
|
+
"ktx",
|
|
675
|
+
"ape",
|
|
676
|
+
"wv",
|
|
677
|
+
"dcm",
|
|
678
|
+
"ics",
|
|
679
|
+
"glb",
|
|
680
|
+
"pcap",
|
|
681
|
+
"dsf",
|
|
682
|
+
"lnk",
|
|
683
|
+
"alias",
|
|
684
|
+
"voc",
|
|
685
|
+
"ac3",
|
|
686
|
+
"m4v",
|
|
687
|
+
"m4p",
|
|
688
|
+
"m4b",
|
|
689
|
+
"f4v",
|
|
690
|
+
"f4p",
|
|
691
|
+
"f4b",
|
|
692
|
+
"f4a",
|
|
693
|
+
"mie",
|
|
694
|
+
"asf",
|
|
695
|
+
"ogm",
|
|
696
|
+
"ogx",
|
|
697
|
+
"mpc",
|
|
698
|
+
"arrow",
|
|
699
|
+
"shp",
|
|
700
|
+
"aac",
|
|
701
|
+
"mp1",
|
|
702
|
+
"it",
|
|
703
|
+
"s3m",
|
|
704
|
+
"xm",
|
|
705
|
+
"skp",
|
|
706
|
+
"avif",
|
|
707
|
+
"eps",
|
|
708
|
+
"lzh",
|
|
709
|
+
"pgp",
|
|
710
|
+
"asar",
|
|
711
|
+
"stl",
|
|
712
|
+
"chm",
|
|
713
|
+
"3mf",
|
|
714
|
+
"zst",
|
|
715
|
+
"jxl",
|
|
716
|
+
"vcf",
|
|
717
|
+
"jls",
|
|
718
|
+
"pst",
|
|
719
|
+
"dwg",
|
|
720
|
+
"parquet",
|
|
721
|
+
"class",
|
|
722
|
+
"arj",
|
|
723
|
+
"cpio",
|
|
724
|
+
"ace",
|
|
725
|
+
"avro",
|
|
726
|
+
"icc",
|
|
727
|
+
"fbx",
|
|
728
|
+
"vsdx",
|
|
729
|
+
"vtt",
|
|
730
|
+
"apk",
|
|
731
|
+
"drc",
|
|
732
|
+
"lz4",
|
|
733
|
+
"potx",
|
|
734
|
+
"xltx",
|
|
735
|
+
"dotx",
|
|
736
|
+
"xltm",
|
|
737
|
+
"ott",
|
|
738
|
+
"ots",
|
|
739
|
+
"otp",
|
|
740
|
+
"odg",
|
|
741
|
+
"otg",
|
|
742
|
+
"xlsm",
|
|
743
|
+
"docm",
|
|
744
|
+
"dotm",
|
|
745
|
+
"potm",
|
|
746
|
+
"pptm",
|
|
747
|
+
"jar",
|
|
748
|
+
"jmp",
|
|
749
|
+
"rm",
|
|
750
|
+
"sav",
|
|
751
|
+
"ppsm",
|
|
752
|
+
"ppsx",
|
|
753
|
+
"tar.gz",
|
|
754
|
+
"reg",
|
|
755
|
+
"dat"
|
|
756
|
+
];
|
|
757
|
+
var mimeTypes = [
|
|
758
|
+
"image/jpeg",
|
|
759
|
+
"image/png",
|
|
760
|
+
"image/gif",
|
|
761
|
+
"image/webp",
|
|
762
|
+
"image/flif",
|
|
763
|
+
"image/x-xcf",
|
|
764
|
+
"image/x-canon-cr2",
|
|
765
|
+
"image/x-canon-cr3",
|
|
766
|
+
"image/tiff",
|
|
767
|
+
"image/bmp",
|
|
768
|
+
"image/vnd.ms-photo",
|
|
769
|
+
"image/vnd.adobe.photoshop",
|
|
770
|
+
"application/x-indesign",
|
|
771
|
+
"application/epub+zip",
|
|
772
|
+
"application/x-xpinstall",
|
|
773
|
+
"application/vnd.ms-powerpoint.slideshow.macroenabled.12",
|
|
774
|
+
"application/vnd.oasis.opendocument.text",
|
|
775
|
+
"application/vnd.oasis.opendocument.spreadsheet",
|
|
776
|
+
"application/vnd.oasis.opendocument.presentation",
|
|
777
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
778
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
779
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
780
|
+
"application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
|
781
|
+
"application/zip",
|
|
782
|
+
"application/x-tar",
|
|
783
|
+
"application/x-rar-compressed",
|
|
784
|
+
"application/gzip",
|
|
785
|
+
"application/x-bzip2",
|
|
786
|
+
"application/x-7z-compressed",
|
|
787
|
+
"application/x-apple-diskimage",
|
|
788
|
+
"application/vnd.apache.arrow.file",
|
|
789
|
+
"video/mp4",
|
|
790
|
+
"audio/midi",
|
|
791
|
+
"video/matroska",
|
|
792
|
+
"video/webm",
|
|
793
|
+
"video/quicktime",
|
|
794
|
+
"video/vnd.avi",
|
|
795
|
+
"audio/wav",
|
|
796
|
+
"audio/qcelp",
|
|
797
|
+
"audio/x-ms-asf",
|
|
798
|
+
"video/x-ms-asf",
|
|
799
|
+
"application/vnd.ms-asf",
|
|
800
|
+
"video/mpeg",
|
|
801
|
+
"video/3gpp",
|
|
802
|
+
"audio/mpeg",
|
|
803
|
+
"audio/mp4",
|
|
804
|
+
// RFC 4337
|
|
805
|
+
"video/ogg",
|
|
806
|
+
"audio/ogg",
|
|
807
|
+
"audio/ogg; codecs=opus",
|
|
808
|
+
"application/ogg",
|
|
809
|
+
"audio/flac",
|
|
810
|
+
"audio/ape",
|
|
811
|
+
"audio/wavpack",
|
|
812
|
+
"audio/amr",
|
|
813
|
+
"application/pdf",
|
|
814
|
+
"application/x-elf",
|
|
815
|
+
"application/x-mach-binary",
|
|
816
|
+
"application/x-msdownload",
|
|
817
|
+
"application/x-shockwave-flash",
|
|
818
|
+
"application/rtf",
|
|
819
|
+
"application/wasm",
|
|
820
|
+
"font/woff",
|
|
821
|
+
"font/woff2",
|
|
822
|
+
"application/vnd.ms-fontobject",
|
|
823
|
+
"font/ttf",
|
|
824
|
+
"font/otf",
|
|
825
|
+
"font/collection",
|
|
826
|
+
"image/x-icon",
|
|
827
|
+
"video/x-flv",
|
|
828
|
+
"application/postscript",
|
|
829
|
+
"application/eps",
|
|
830
|
+
"application/x-xz",
|
|
831
|
+
"application/x-sqlite3",
|
|
832
|
+
"application/x-nintendo-nes-rom",
|
|
833
|
+
"application/x-google-chrome-extension",
|
|
834
|
+
"application/vnd.ms-cab-compressed",
|
|
835
|
+
"application/x-deb",
|
|
836
|
+
"application/x-unix-archive",
|
|
837
|
+
"application/x-rpm",
|
|
838
|
+
"application/x-compress",
|
|
839
|
+
"application/x-lzip",
|
|
840
|
+
"application/x-cfb",
|
|
841
|
+
"application/x-mie",
|
|
842
|
+
"application/mxf",
|
|
843
|
+
"video/mp2t",
|
|
844
|
+
"application/x-blender",
|
|
845
|
+
"image/bpg",
|
|
846
|
+
"image/j2c",
|
|
847
|
+
"image/jp2",
|
|
848
|
+
"image/jpx",
|
|
849
|
+
"image/jpm",
|
|
850
|
+
"image/mj2",
|
|
851
|
+
"audio/aiff",
|
|
852
|
+
"application/xml",
|
|
853
|
+
"application/x-mobipocket-ebook",
|
|
854
|
+
"image/heif",
|
|
855
|
+
"image/heif-sequence",
|
|
856
|
+
"image/heic",
|
|
857
|
+
"image/heic-sequence",
|
|
858
|
+
"image/icns",
|
|
859
|
+
"image/ktx",
|
|
860
|
+
"application/dicom",
|
|
861
|
+
"audio/x-musepack",
|
|
862
|
+
"text/calendar",
|
|
863
|
+
"text/vcard",
|
|
864
|
+
"text/vtt",
|
|
865
|
+
"model/gltf-binary",
|
|
866
|
+
"application/vnd.tcpdump.pcap",
|
|
867
|
+
"audio/x-dsf",
|
|
868
|
+
// Non-standard
|
|
869
|
+
"application/x.ms.shortcut",
|
|
870
|
+
// Invented by us
|
|
871
|
+
"application/x.apple.alias",
|
|
872
|
+
// Invented by us
|
|
873
|
+
"audio/x-voc",
|
|
874
|
+
"audio/vnd.dolby.dd-raw",
|
|
875
|
+
"audio/x-m4a",
|
|
876
|
+
"image/apng",
|
|
877
|
+
"image/x-olympus-orf",
|
|
878
|
+
"image/x-sony-arw",
|
|
879
|
+
"image/x-adobe-dng",
|
|
880
|
+
"image/x-nikon-nef",
|
|
881
|
+
"image/x-panasonic-rw2",
|
|
882
|
+
"image/x-fujifilm-raf",
|
|
883
|
+
"video/x-m4v",
|
|
884
|
+
"video/3gpp2",
|
|
885
|
+
"application/x-esri-shape",
|
|
886
|
+
"audio/aac",
|
|
887
|
+
"audio/x-it",
|
|
888
|
+
"audio/x-s3m",
|
|
889
|
+
"audio/x-xm",
|
|
890
|
+
"video/MP1S",
|
|
891
|
+
"video/MP2P",
|
|
892
|
+
"application/vnd.sketchup.skp",
|
|
893
|
+
"image/avif",
|
|
894
|
+
"application/x-lzh-compressed",
|
|
895
|
+
"application/pgp-encrypted",
|
|
896
|
+
"application/x-asar",
|
|
897
|
+
"model/stl",
|
|
898
|
+
"application/vnd.ms-htmlhelp",
|
|
899
|
+
"model/3mf",
|
|
900
|
+
"image/jxl",
|
|
901
|
+
"application/zstd",
|
|
902
|
+
"image/jls",
|
|
903
|
+
"application/vnd.ms-outlook",
|
|
904
|
+
"image/vnd.dwg",
|
|
905
|
+
"application/vnd.apache.parquet",
|
|
906
|
+
"application/java-vm",
|
|
907
|
+
"application/x-arj",
|
|
908
|
+
"application/x-cpio",
|
|
909
|
+
"application/x-ace-compressed",
|
|
910
|
+
"application/avro",
|
|
911
|
+
"application/vnd.iccprofile",
|
|
912
|
+
"application/x.autodesk.fbx",
|
|
913
|
+
// Invented by us
|
|
914
|
+
"application/vnd.visio",
|
|
915
|
+
"application/vnd.android.package-archive",
|
|
916
|
+
"application/vnd.google.draco",
|
|
917
|
+
// Invented by us
|
|
918
|
+
"application/x-lz4",
|
|
919
|
+
// Invented by us
|
|
920
|
+
"application/vnd.openxmlformats-officedocument.presentationml.template",
|
|
921
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
|
922
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
|
923
|
+
"application/vnd.ms-excel.template.macroenabled.12",
|
|
924
|
+
"application/vnd.oasis.opendocument.text-template",
|
|
925
|
+
"application/vnd.oasis.opendocument.spreadsheet-template",
|
|
926
|
+
"application/vnd.oasis.opendocument.presentation-template",
|
|
927
|
+
"application/vnd.oasis.opendocument.graphics",
|
|
928
|
+
"application/vnd.oasis.opendocument.graphics-template",
|
|
929
|
+
"application/vnd.ms-excel.sheet.macroenabled.12",
|
|
930
|
+
"application/vnd.ms-word.document.macroenabled.12",
|
|
931
|
+
"application/vnd.ms-word.template.macroenabled.12",
|
|
932
|
+
"application/vnd.ms-powerpoint.template.macroenabled.12",
|
|
933
|
+
"application/vnd.ms-powerpoint.presentation.macroenabled.12",
|
|
934
|
+
"application/java-archive",
|
|
935
|
+
"application/vnd.rn-realmedia",
|
|
936
|
+
"application/x-spss-sav",
|
|
937
|
+
"application/x-ms-regedit",
|
|
938
|
+
"application/x-ft-windows-registry-hive",
|
|
939
|
+
"application/x-jmp-data"
|
|
940
|
+
];
|
|
941
|
+
|
|
942
|
+
// ../../node_modules/.pnpm/file-type@21.3.0/node_modules/file-type/core.js
|
|
943
|
+
var reasonableDetectionSizeInBytes = 4100;
|
|
944
|
+
async function fileTypeFromBuffer(input, options) {
|
|
945
|
+
return new FileTypeParser(options).fromBuffer(input);
|
|
946
|
+
}
|
|
947
|
+
function getFileTypeFromMimeType(mimeType) {
|
|
948
|
+
mimeType = mimeType.toLowerCase();
|
|
949
|
+
switch (mimeType) {
|
|
950
|
+
case "application/epub+zip":
|
|
951
|
+
return {
|
|
952
|
+
ext: "epub",
|
|
953
|
+
mime: mimeType
|
|
954
|
+
};
|
|
955
|
+
case "application/vnd.oasis.opendocument.text":
|
|
956
|
+
return {
|
|
957
|
+
ext: "odt",
|
|
958
|
+
mime: mimeType
|
|
959
|
+
};
|
|
960
|
+
case "application/vnd.oasis.opendocument.text-template":
|
|
961
|
+
return {
|
|
962
|
+
ext: "ott",
|
|
963
|
+
mime: mimeType
|
|
964
|
+
};
|
|
965
|
+
case "application/vnd.oasis.opendocument.spreadsheet":
|
|
966
|
+
return {
|
|
967
|
+
ext: "ods",
|
|
968
|
+
mime: mimeType
|
|
969
|
+
};
|
|
970
|
+
case "application/vnd.oasis.opendocument.spreadsheet-template":
|
|
971
|
+
return {
|
|
972
|
+
ext: "ots",
|
|
973
|
+
mime: mimeType
|
|
974
|
+
};
|
|
975
|
+
case "application/vnd.oasis.opendocument.presentation":
|
|
976
|
+
return {
|
|
977
|
+
ext: "odp",
|
|
978
|
+
mime: mimeType
|
|
979
|
+
};
|
|
980
|
+
case "application/vnd.oasis.opendocument.presentation-template":
|
|
981
|
+
return {
|
|
982
|
+
ext: "otp",
|
|
983
|
+
mime: mimeType
|
|
984
|
+
};
|
|
985
|
+
case "application/vnd.oasis.opendocument.graphics":
|
|
986
|
+
return {
|
|
987
|
+
ext: "odg",
|
|
988
|
+
mime: mimeType
|
|
989
|
+
};
|
|
990
|
+
case "application/vnd.oasis.opendocument.graphics-template":
|
|
991
|
+
return {
|
|
992
|
+
ext: "otg",
|
|
993
|
+
mime: mimeType
|
|
994
|
+
};
|
|
995
|
+
case "application/vnd.openxmlformats-officedocument.presentationml.slideshow":
|
|
996
|
+
return {
|
|
997
|
+
ext: "ppsx",
|
|
998
|
+
mime: mimeType
|
|
999
|
+
};
|
|
1000
|
+
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
|
1001
|
+
return {
|
|
1002
|
+
ext: "xlsx",
|
|
1003
|
+
mime: mimeType
|
|
1004
|
+
};
|
|
1005
|
+
case "application/vnd.ms-excel.sheet.macroenabled":
|
|
1006
|
+
return {
|
|
1007
|
+
ext: "xlsm",
|
|
1008
|
+
mime: "application/vnd.ms-excel.sheet.macroenabled.12"
|
|
1009
|
+
};
|
|
1010
|
+
case "application/vnd.openxmlformats-officedocument.spreadsheetml.template":
|
|
1011
|
+
return {
|
|
1012
|
+
ext: "xltx",
|
|
1013
|
+
mime: mimeType
|
|
1014
|
+
};
|
|
1015
|
+
case "application/vnd.ms-excel.template.macroenabled":
|
|
1016
|
+
return {
|
|
1017
|
+
ext: "xltm",
|
|
1018
|
+
mime: "application/vnd.ms-excel.template.macroenabled.12"
|
|
1019
|
+
};
|
|
1020
|
+
case "application/vnd.ms-powerpoint.slideshow.macroenabled":
|
|
1021
|
+
return {
|
|
1022
|
+
ext: "ppsm",
|
|
1023
|
+
mime: "application/vnd.ms-powerpoint.slideshow.macroenabled.12"
|
|
1024
|
+
};
|
|
1025
|
+
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
|
1026
|
+
return {
|
|
1027
|
+
ext: "docx",
|
|
1028
|
+
mime: mimeType
|
|
1029
|
+
};
|
|
1030
|
+
case "application/vnd.ms-word.document.macroenabled":
|
|
1031
|
+
return {
|
|
1032
|
+
ext: "docm",
|
|
1033
|
+
mime: "application/vnd.ms-word.document.macroenabled.12"
|
|
1034
|
+
};
|
|
1035
|
+
case "application/vnd.openxmlformats-officedocument.wordprocessingml.template":
|
|
1036
|
+
return {
|
|
1037
|
+
ext: "dotx",
|
|
1038
|
+
mime: mimeType
|
|
1039
|
+
};
|
|
1040
|
+
case "application/vnd.ms-word.template.macroenabledtemplate":
|
|
1041
|
+
return {
|
|
1042
|
+
ext: "dotm",
|
|
1043
|
+
mime: "application/vnd.ms-word.template.macroenabled.12"
|
|
1044
|
+
};
|
|
1045
|
+
case "application/vnd.openxmlformats-officedocument.presentationml.template":
|
|
1046
|
+
return {
|
|
1047
|
+
ext: "potx",
|
|
1048
|
+
mime: mimeType
|
|
1049
|
+
};
|
|
1050
|
+
case "application/vnd.ms-powerpoint.template.macroenabled":
|
|
1051
|
+
return {
|
|
1052
|
+
ext: "potm",
|
|
1053
|
+
mime: "application/vnd.ms-powerpoint.template.macroenabled.12"
|
|
1054
|
+
};
|
|
1055
|
+
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
|
|
1056
|
+
return {
|
|
1057
|
+
ext: "pptx",
|
|
1058
|
+
mime: mimeType
|
|
1059
|
+
};
|
|
1060
|
+
case "application/vnd.ms-powerpoint.presentation.macroenabled":
|
|
1061
|
+
return {
|
|
1062
|
+
ext: "pptm",
|
|
1063
|
+
mime: "application/vnd.ms-powerpoint.presentation.macroenabled.12"
|
|
1064
|
+
};
|
|
1065
|
+
case "application/vnd.ms-visio.drawing":
|
|
1066
|
+
return {
|
|
1067
|
+
ext: "vsdx",
|
|
1068
|
+
mime: "application/vnd.visio"
|
|
1069
|
+
};
|
|
1070
|
+
case "application/vnd.ms-package.3dmanufacturing-3dmodel+xml":
|
|
1071
|
+
return {
|
|
1072
|
+
ext: "3mf",
|
|
1073
|
+
mime: "model/3mf"
|
|
1074
|
+
};
|
|
1075
|
+
default:
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
function _check(buffer, headers, options) {
|
|
1079
|
+
options = {
|
|
1080
|
+
offset: 0,
|
|
1081
|
+
...options
|
|
1082
|
+
};
|
|
1083
|
+
for (const [index, header] of headers.entries()) {
|
|
1084
|
+
if (options.mask) {
|
|
1085
|
+
if (header !== (options.mask[index] & buffer[index + options.offset])) {
|
|
1086
|
+
return false;
|
|
1087
|
+
}
|
|
1088
|
+
} else if (header !== buffer[index + options.offset]) {
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return true;
|
|
1093
|
+
}
|
|
1094
|
+
var FileTypeParser = class {
|
|
1095
|
+
constructor(options) {
|
|
1096
|
+
this.options = {
|
|
1097
|
+
mpegOffsetTolerance: 0,
|
|
1098
|
+
...options
|
|
1099
|
+
};
|
|
1100
|
+
this.detectors = [
|
|
1101
|
+
...options?.customDetectors ?? [],
|
|
1102
|
+
{ id: "core", detect: this.detectConfident },
|
|
1103
|
+
{ id: "core.imprecise", detect: this.detectImprecise }
|
|
1104
|
+
];
|
|
1105
|
+
this.tokenizerOptions = {
|
|
1106
|
+
abortSignal: options?.signal
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
async fromTokenizer(tokenizer) {
|
|
1110
|
+
const initialPosition = tokenizer.position;
|
|
1111
|
+
for (const detector of this.detectors) {
|
|
1112
|
+
const fileType = await detector.detect(tokenizer);
|
|
1113
|
+
if (fileType) {
|
|
1114
|
+
return fileType;
|
|
1115
|
+
}
|
|
1116
|
+
if (initialPosition !== tokenizer.position) {
|
|
1117
|
+
return void 0;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
async fromBuffer(input) {
|
|
1122
|
+
if (!(input instanceof Uint8Array || input instanceof ArrayBuffer)) {
|
|
1123
|
+
throw new TypeError(`Expected the \`input\` argument to be of type \`Uint8Array\` or \`ArrayBuffer\`, got \`${typeof input}\``);
|
|
1124
|
+
}
|
|
1125
|
+
const buffer = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
1126
|
+
if (!(buffer?.length > 1)) {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
return this.fromTokenizer(fromBuffer(buffer, this.tokenizerOptions));
|
|
1130
|
+
}
|
|
1131
|
+
async fromBlob(blob) {
|
|
1132
|
+
const tokenizer = fromBlob(blob, this.tokenizerOptions);
|
|
1133
|
+
try {
|
|
1134
|
+
return await this.fromTokenizer(tokenizer);
|
|
1135
|
+
} finally {
|
|
1136
|
+
await tokenizer.close();
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
async fromStream(stream) {
|
|
1140
|
+
const tokenizer = fromWebStream(stream, this.tokenizerOptions);
|
|
1141
|
+
try {
|
|
1142
|
+
return await this.fromTokenizer(tokenizer);
|
|
1143
|
+
} finally {
|
|
1144
|
+
await tokenizer.close();
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
async toDetectionStream(stream, options) {
|
|
1148
|
+
const { sampleSize = reasonableDetectionSizeInBytes } = options;
|
|
1149
|
+
let detectedFileType;
|
|
1150
|
+
let firstChunk;
|
|
1151
|
+
const reader = stream.getReader({ mode: "byob" });
|
|
1152
|
+
try {
|
|
1153
|
+
const { value: chunk, done } = await reader.read(new Uint8Array(sampleSize));
|
|
1154
|
+
firstChunk = chunk;
|
|
1155
|
+
if (!done && chunk) {
|
|
1156
|
+
try {
|
|
1157
|
+
detectedFileType = await this.fromBuffer(chunk.subarray(0, sampleSize));
|
|
1158
|
+
} catch (error) {
|
|
1159
|
+
if (!(error instanceof EndOfStreamError)) {
|
|
1160
|
+
throw error;
|
|
1161
|
+
}
|
|
1162
|
+
detectedFileType = void 0;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
firstChunk = chunk;
|
|
1166
|
+
} finally {
|
|
1167
|
+
reader.releaseLock();
|
|
1168
|
+
}
|
|
1169
|
+
const transformStream = new TransformStream({
|
|
1170
|
+
async start(controller) {
|
|
1171
|
+
controller.enqueue(firstChunk);
|
|
1172
|
+
},
|
|
1173
|
+
transform(chunk, controller) {
|
|
1174
|
+
controller.enqueue(chunk);
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
const newStream = stream.pipeThrough(transformStream);
|
|
1178
|
+
newStream.fileType = detectedFileType;
|
|
1179
|
+
return newStream;
|
|
1180
|
+
}
|
|
1181
|
+
check(header, options) {
|
|
1182
|
+
return _check(this.buffer, header, options);
|
|
1183
|
+
}
|
|
1184
|
+
checkString(header, options) {
|
|
1185
|
+
return this.check(stringToBytes(header, options?.encoding), options);
|
|
1186
|
+
}
|
|
1187
|
+
// Detections with a high degree of certainty in identifying the correct file type
|
|
1188
|
+
detectConfident = async (tokenizer) => {
|
|
1189
|
+
this.buffer = new Uint8Array(reasonableDetectionSizeInBytes);
|
|
1190
|
+
if (tokenizer.fileInfo.size === void 0) {
|
|
1191
|
+
tokenizer.fileInfo.size = Number.MAX_SAFE_INTEGER;
|
|
1192
|
+
}
|
|
1193
|
+
this.tokenizer = tokenizer;
|
|
1194
|
+
await tokenizer.peekBuffer(this.buffer, { length: 32, mayBeLess: true });
|
|
1195
|
+
if (this.check([66, 77])) {
|
|
1196
|
+
return {
|
|
1197
|
+
ext: "bmp",
|
|
1198
|
+
mime: "image/bmp"
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
if (this.check([11, 119])) {
|
|
1202
|
+
return {
|
|
1203
|
+
ext: "ac3",
|
|
1204
|
+
mime: "audio/vnd.dolby.dd-raw"
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
if (this.check([120, 1])) {
|
|
1208
|
+
return {
|
|
1209
|
+
ext: "dmg",
|
|
1210
|
+
mime: "application/x-apple-diskimage"
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
if (this.check([77, 90])) {
|
|
1214
|
+
return {
|
|
1215
|
+
ext: "exe",
|
|
1216
|
+
mime: "application/x-msdownload"
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
if (this.check([37, 33])) {
|
|
1220
|
+
await tokenizer.peekBuffer(this.buffer, { length: 24, mayBeLess: true });
|
|
1221
|
+
if (this.checkString("PS-Adobe-", { offset: 2 }) && this.checkString(" EPSF-", { offset: 14 })) {
|
|
1222
|
+
return {
|
|
1223
|
+
ext: "eps",
|
|
1224
|
+
mime: "application/eps"
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
return {
|
|
1228
|
+
ext: "ps",
|
|
1229
|
+
mime: "application/postscript"
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
if (this.check([31, 160]) || this.check([31, 157])) {
|
|
1233
|
+
return {
|
|
1234
|
+
ext: "Z",
|
|
1235
|
+
mime: "application/x-compress"
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
if (this.check([199, 113])) {
|
|
1239
|
+
return {
|
|
1240
|
+
ext: "cpio",
|
|
1241
|
+
mime: "application/x-cpio"
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
if (this.check([96, 234])) {
|
|
1245
|
+
return {
|
|
1246
|
+
ext: "arj",
|
|
1247
|
+
mime: "application/x-arj"
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
if (this.check([239, 187, 191])) {
|
|
1251
|
+
this.tokenizer.ignore(3);
|
|
1252
|
+
return this.detectConfident(tokenizer);
|
|
1253
|
+
}
|
|
1254
|
+
if (this.check([71, 73, 70])) {
|
|
1255
|
+
return {
|
|
1256
|
+
ext: "gif",
|
|
1257
|
+
mime: "image/gif"
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
if (this.check([73, 73, 188])) {
|
|
1261
|
+
return {
|
|
1262
|
+
ext: "jxr",
|
|
1263
|
+
mime: "image/vnd.ms-photo"
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
if (this.check([31, 139, 8])) {
|
|
1267
|
+
const gzipHandler = new GzipHandler(tokenizer);
|
|
1268
|
+
const stream = gzipHandler.inflate();
|
|
1269
|
+
let shouldCancelStream = true;
|
|
1270
|
+
try {
|
|
1271
|
+
let compressedFileType;
|
|
1272
|
+
try {
|
|
1273
|
+
compressedFileType = await this.fromStream(stream);
|
|
1274
|
+
} catch {
|
|
1275
|
+
shouldCancelStream = false;
|
|
1276
|
+
}
|
|
1277
|
+
if (compressedFileType && compressedFileType.ext === "tar") {
|
|
1278
|
+
return {
|
|
1279
|
+
ext: "tar.gz",
|
|
1280
|
+
mime: "application/gzip"
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
} finally {
|
|
1284
|
+
if (shouldCancelStream) {
|
|
1285
|
+
await stream.cancel();
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return {
|
|
1289
|
+
ext: "gz",
|
|
1290
|
+
mime: "application/gzip"
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
if (this.check([66, 90, 104])) {
|
|
1294
|
+
return {
|
|
1295
|
+
ext: "bz2",
|
|
1296
|
+
mime: "application/x-bzip2"
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
if (this.checkString("ID3")) {
|
|
1300
|
+
await tokenizer.ignore(6);
|
|
1301
|
+
const id3HeaderLength = await tokenizer.readToken(uint32SyncSafeToken);
|
|
1302
|
+
if (tokenizer.position + id3HeaderLength > tokenizer.fileInfo.size) {
|
|
1303
|
+
return {
|
|
1304
|
+
ext: "mp3",
|
|
1305
|
+
mime: "audio/mpeg"
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
await tokenizer.ignore(id3HeaderLength);
|
|
1309
|
+
return this.fromTokenizer(tokenizer);
|
|
1310
|
+
}
|
|
1311
|
+
if (this.checkString("MP+")) {
|
|
1312
|
+
return {
|
|
1313
|
+
ext: "mpc",
|
|
1314
|
+
mime: "audio/x-musepack"
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
if ((this.buffer[0] === 67 || this.buffer[0] === 70) && this.check([87, 83], { offset: 1 })) {
|
|
1318
|
+
return {
|
|
1319
|
+
ext: "swf",
|
|
1320
|
+
mime: "application/x-shockwave-flash"
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
if (this.check([255, 216, 255])) {
|
|
1324
|
+
if (this.check([247], { offset: 3 })) {
|
|
1325
|
+
return {
|
|
1326
|
+
ext: "jls",
|
|
1327
|
+
mime: "image/jls"
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
return {
|
|
1331
|
+
ext: "jpg",
|
|
1332
|
+
mime: "image/jpeg"
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
if (this.check([79, 98, 106, 1])) {
|
|
1336
|
+
return {
|
|
1337
|
+
ext: "avro",
|
|
1338
|
+
mime: "application/avro"
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
if (this.checkString("FLIF")) {
|
|
1342
|
+
return {
|
|
1343
|
+
ext: "flif",
|
|
1344
|
+
mime: "image/flif"
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
if (this.checkString("8BPS")) {
|
|
1348
|
+
return {
|
|
1349
|
+
ext: "psd",
|
|
1350
|
+
mime: "image/vnd.adobe.photoshop"
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
if (this.checkString("MPCK")) {
|
|
1354
|
+
return {
|
|
1355
|
+
ext: "mpc",
|
|
1356
|
+
mime: "audio/x-musepack"
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
if (this.checkString("FORM")) {
|
|
1360
|
+
return {
|
|
1361
|
+
ext: "aif",
|
|
1362
|
+
mime: "audio/aiff"
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
if (this.checkString("icns", { offset: 0 })) {
|
|
1366
|
+
return {
|
|
1367
|
+
ext: "icns",
|
|
1368
|
+
mime: "image/icns"
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
if (this.check([80, 75, 3, 4])) {
|
|
1372
|
+
let fileType;
|
|
1373
|
+
await new ZipHandler(tokenizer).unzip((zipHeader) => {
|
|
1374
|
+
switch (zipHeader.filename) {
|
|
1375
|
+
case "META-INF/mozilla.rsa":
|
|
1376
|
+
fileType = {
|
|
1377
|
+
ext: "xpi",
|
|
1378
|
+
mime: "application/x-xpinstall"
|
|
1379
|
+
};
|
|
1380
|
+
return {
|
|
1381
|
+
stop: true
|
|
1382
|
+
};
|
|
1383
|
+
case "META-INF/MANIFEST.MF":
|
|
1384
|
+
fileType = {
|
|
1385
|
+
ext: "jar",
|
|
1386
|
+
mime: "application/java-archive"
|
|
1387
|
+
};
|
|
1388
|
+
return {
|
|
1389
|
+
stop: true
|
|
1390
|
+
};
|
|
1391
|
+
case "mimetype":
|
|
1392
|
+
return {
|
|
1393
|
+
async handler(fileData) {
|
|
1394
|
+
const mimeType = new TextDecoder("utf-8").decode(fileData).trim();
|
|
1395
|
+
fileType = getFileTypeFromMimeType(mimeType);
|
|
1396
|
+
},
|
|
1397
|
+
stop: true
|
|
1398
|
+
};
|
|
1399
|
+
case "[Content_Types].xml":
|
|
1400
|
+
return {
|
|
1401
|
+
async handler(fileData) {
|
|
1402
|
+
let xmlContent = new TextDecoder("utf-8").decode(fileData);
|
|
1403
|
+
const endPos = xmlContent.indexOf('.main+xml"');
|
|
1404
|
+
if (endPos === -1) {
|
|
1405
|
+
const mimeType = "application/vnd.ms-package.3dmanufacturing-3dmodel+xml";
|
|
1406
|
+
if (xmlContent.includes(`ContentType="${mimeType}"`)) {
|
|
1407
|
+
fileType = getFileTypeFromMimeType(mimeType);
|
|
1408
|
+
}
|
|
1409
|
+
} else {
|
|
1410
|
+
xmlContent = xmlContent.slice(0, Math.max(0, endPos));
|
|
1411
|
+
const firstPos = xmlContent.lastIndexOf('"');
|
|
1412
|
+
const mimeType = xmlContent.slice(Math.max(0, firstPos + 1));
|
|
1413
|
+
fileType = getFileTypeFromMimeType(mimeType);
|
|
1414
|
+
}
|
|
1415
|
+
},
|
|
1416
|
+
stop: true
|
|
1417
|
+
};
|
|
1418
|
+
default:
|
|
1419
|
+
if (/classes\d*\.dex/.test(zipHeader.filename)) {
|
|
1420
|
+
fileType = {
|
|
1421
|
+
ext: "apk",
|
|
1422
|
+
mime: "application/vnd.android.package-archive"
|
|
1423
|
+
};
|
|
1424
|
+
return { stop: true };
|
|
1425
|
+
}
|
|
1426
|
+
return {};
|
|
1427
|
+
}
|
|
1428
|
+
}).catch((error) => {
|
|
1429
|
+
if (!(error instanceof EndOfStreamError)) {
|
|
1430
|
+
throw error;
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1433
|
+
return fileType ?? {
|
|
1434
|
+
ext: "zip",
|
|
1435
|
+
mime: "application/zip"
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
if (this.checkString("OggS")) {
|
|
1439
|
+
await tokenizer.ignore(28);
|
|
1440
|
+
const type = new Uint8Array(8);
|
|
1441
|
+
await tokenizer.readBuffer(type);
|
|
1442
|
+
if (_check(type, [79, 112, 117, 115, 72, 101, 97, 100])) {
|
|
1443
|
+
return {
|
|
1444
|
+
ext: "opus",
|
|
1445
|
+
mime: "audio/ogg; codecs=opus"
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
if (_check(type, [128, 116, 104, 101, 111, 114, 97])) {
|
|
1449
|
+
return {
|
|
1450
|
+
ext: "ogv",
|
|
1451
|
+
mime: "video/ogg"
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
if (_check(type, [1, 118, 105, 100, 101, 111, 0])) {
|
|
1455
|
+
return {
|
|
1456
|
+
ext: "ogm",
|
|
1457
|
+
mime: "video/ogg"
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
if (_check(type, [127, 70, 76, 65, 67])) {
|
|
1461
|
+
return {
|
|
1462
|
+
ext: "oga",
|
|
1463
|
+
mime: "audio/ogg"
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
if (_check(type, [83, 112, 101, 101, 120, 32, 32])) {
|
|
1467
|
+
return {
|
|
1468
|
+
ext: "spx",
|
|
1469
|
+
mime: "audio/ogg"
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
if (_check(type, [1, 118, 111, 114, 98, 105, 115])) {
|
|
1473
|
+
return {
|
|
1474
|
+
ext: "ogg",
|
|
1475
|
+
mime: "audio/ogg"
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
return {
|
|
1479
|
+
ext: "ogx",
|
|
1480
|
+
mime: "application/ogg"
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
if (this.check([80, 75]) && (this.buffer[2] === 3 || this.buffer[2] === 5 || this.buffer[2] === 7) && (this.buffer[3] === 4 || this.buffer[3] === 6 || this.buffer[3] === 8)) {
|
|
1484
|
+
return {
|
|
1485
|
+
ext: "zip",
|
|
1486
|
+
mime: "application/zip"
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
if (this.checkString("MThd")) {
|
|
1490
|
+
return {
|
|
1491
|
+
ext: "mid",
|
|
1492
|
+
mime: "audio/midi"
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
if (this.checkString("wOFF") && (this.check([0, 1, 0, 0], { offset: 4 }) || this.checkString("OTTO", { offset: 4 }))) {
|
|
1496
|
+
return {
|
|
1497
|
+
ext: "woff",
|
|
1498
|
+
mime: "font/woff"
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
1501
|
+
if (this.checkString("wOF2") && (this.check([0, 1, 0, 0], { offset: 4 }) || this.checkString("OTTO", { offset: 4 }))) {
|
|
1502
|
+
return {
|
|
1503
|
+
ext: "woff2",
|
|
1504
|
+
mime: "font/woff2"
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
if (this.check([212, 195, 178, 161]) || this.check([161, 178, 195, 212])) {
|
|
1508
|
+
return {
|
|
1509
|
+
ext: "pcap",
|
|
1510
|
+
mime: "application/vnd.tcpdump.pcap"
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
if (this.checkString("DSD ")) {
|
|
1514
|
+
return {
|
|
1515
|
+
ext: "dsf",
|
|
1516
|
+
mime: "audio/x-dsf"
|
|
1517
|
+
// Non-standard
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
if (this.checkString("LZIP")) {
|
|
1521
|
+
return {
|
|
1522
|
+
ext: "lz",
|
|
1523
|
+
mime: "application/x-lzip"
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
if (this.checkString("fLaC")) {
|
|
1527
|
+
return {
|
|
1528
|
+
ext: "flac",
|
|
1529
|
+
mime: "audio/flac"
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
if (this.check([66, 80, 71, 251])) {
|
|
1533
|
+
return {
|
|
1534
|
+
ext: "bpg",
|
|
1535
|
+
mime: "image/bpg"
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
if (this.checkString("wvpk")) {
|
|
1539
|
+
return {
|
|
1540
|
+
ext: "wv",
|
|
1541
|
+
mime: "audio/wavpack"
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
if (this.checkString("%PDF")) {
|
|
1545
|
+
return {
|
|
1546
|
+
ext: "pdf",
|
|
1547
|
+
mime: "application/pdf"
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
if (this.check([0, 97, 115, 109])) {
|
|
1551
|
+
return {
|
|
1552
|
+
ext: "wasm",
|
|
1553
|
+
mime: "application/wasm"
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
if (this.check([73, 73])) {
|
|
1557
|
+
const fileType = await this.readTiffHeader(false);
|
|
1558
|
+
if (fileType) {
|
|
1559
|
+
return fileType;
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
if (this.check([77, 77])) {
|
|
1563
|
+
const fileType = await this.readTiffHeader(true);
|
|
1564
|
+
if (fileType) {
|
|
1565
|
+
return fileType;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
if (this.checkString("MAC ")) {
|
|
1569
|
+
return {
|
|
1570
|
+
ext: "ape",
|
|
1571
|
+
mime: "audio/ape"
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
if (this.check([26, 69, 223, 163])) {
|
|
1575
|
+
async function readField() {
|
|
1576
|
+
const msb = await tokenizer.peekNumber(UINT8);
|
|
1577
|
+
let mask = 128;
|
|
1578
|
+
let ic = 0;
|
|
1579
|
+
while ((msb & mask) === 0 && mask !== 0) {
|
|
1580
|
+
++ic;
|
|
1581
|
+
mask >>= 1;
|
|
1582
|
+
}
|
|
1583
|
+
const id = new Uint8Array(ic + 1);
|
|
1584
|
+
await tokenizer.readBuffer(id);
|
|
1585
|
+
return id;
|
|
1586
|
+
}
|
|
1587
|
+
async function readElement() {
|
|
1588
|
+
const idField = await readField();
|
|
1589
|
+
const lengthField = await readField();
|
|
1590
|
+
lengthField[0] ^= 128 >> lengthField.length - 1;
|
|
1591
|
+
const nrLength = Math.min(6, lengthField.length);
|
|
1592
|
+
const idView = new DataView(idField.buffer);
|
|
1593
|
+
const lengthView = new DataView(lengthField.buffer, lengthField.length - nrLength, nrLength);
|
|
1594
|
+
return {
|
|
1595
|
+
id: getUintBE(idView),
|
|
1596
|
+
len: getUintBE(lengthView)
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
async function readChildren(children) {
|
|
1600
|
+
while (children > 0) {
|
|
1601
|
+
const element = await readElement();
|
|
1602
|
+
if (element.id === 17026) {
|
|
1603
|
+
const rawValue = await tokenizer.readToken(new StringType(element.len));
|
|
1604
|
+
return rawValue.replaceAll(/\00.*$/g, "");
|
|
1605
|
+
}
|
|
1606
|
+
await tokenizer.ignore(element.len);
|
|
1607
|
+
--children;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
const re = await readElement();
|
|
1611
|
+
const documentType = await readChildren(re.len);
|
|
1612
|
+
switch (documentType) {
|
|
1613
|
+
case "webm":
|
|
1614
|
+
return {
|
|
1615
|
+
ext: "webm",
|
|
1616
|
+
mime: "video/webm"
|
|
1617
|
+
};
|
|
1618
|
+
case "matroska":
|
|
1619
|
+
return {
|
|
1620
|
+
ext: "mkv",
|
|
1621
|
+
mime: "video/matroska"
|
|
1622
|
+
};
|
|
1623
|
+
default:
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
if (this.checkString("SQLi")) {
|
|
1628
|
+
return {
|
|
1629
|
+
ext: "sqlite",
|
|
1630
|
+
mime: "application/x-sqlite3"
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
if (this.check([78, 69, 83, 26])) {
|
|
1634
|
+
return {
|
|
1635
|
+
ext: "nes",
|
|
1636
|
+
mime: "application/x-nintendo-nes-rom"
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
if (this.checkString("Cr24")) {
|
|
1640
|
+
return {
|
|
1641
|
+
ext: "crx",
|
|
1642
|
+
mime: "application/x-google-chrome-extension"
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
if (this.checkString("MSCF") || this.checkString("ISc(")) {
|
|
1646
|
+
return {
|
|
1647
|
+
ext: "cab",
|
|
1648
|
+
mime: "application/vnd.ms-cab-compressed"
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
if (this.check([237, 171, 238, 219])) {
|
|
1652
|
+
return {
|
|
1653
|
+
ext: "rpm",
|
|
1654
|
+
mime: "application/x-rpm"
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
if (this.check([197, 208, 211, 198])) {
|
|
1658
|
+
return {
|
|
1659
|
+
ext: "eps",
|
|
1660
|
+
mime: "application/eps"
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
if (this.check([40, 181, 47, 253])) {
|
|
1664
|
+
return {
|
|
1665
|
+
ext: "zst",
|
|
1666
|
+
mime: "application/zstd"
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
if (this.check([127, 69, 76, 70])) {
|
|
1670
|
+
return {
|
|
1671
|
+
ext: "elf",
|
|
1672
|
+
mime: "application/x-elf"
|
|
1673
|
+
};
|
|
1674
|
+
}
|
|
1675
|
+
if (this.check([33, 66, 68, 78])) {
|
|
1676
|
+
return {
|
|
1677
|
+
ext: "pst",
|
|
1678
|
+
mime: "application/vnd.ms-outlook"
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
if (this.checkString("PAR1") || this.checkString("PARE")) {
|
|
1682
|
+
return {
|
|
1683
|
+
ext: "parquet",
|
|
1684
|
+
mime: "application/vnd.apache.parquet"
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
if (this.checkString("ttcf")) {
|
|
1688
|
+
return {
|
|
1689
|
+
ext: "ttc",
|
|
1690
|
+
mime: "font/collection"
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
if (this.check([254, 237, 250, 206]) || this.check([254, 237, 250, 207]) || this.check([206, 250, 237, 254]) || this.check([207, 250, 237, 254])) {
|
|
1694
|
+
return {
|
|
1695
|
+
ext: "macho",
|
|
1696
|
+
mime: "application/x-mach-binary"
|
|
1697
|
+
};
|
|
1698
|
+
}
|
|
1699
|
+
if (this.check([4, 34, 77, 24])) {
|
|
1700
|
+
return {
|
|
1701
|
+
ext: "lz4",
|
|
1702
|
+
mime: "application/x-lz4"
|
|
1703
|
+
// Invented by us
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
if (this.checkString("regf")) {
|
|
1707
|
+
return {
|
|
1708
|
+
ext: "dat",
|
|
1709
|
+
mime: "application/x-ft-windows-registry-hive"
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
if (this.checkString("$FL2") || this.checkString("$FL3")) {
|
|
1713
|
+
return {
|
|
1714
|
+
ext: "sav",
|
|
1715
|
+
mime: "application/x-spss-sav"
|
|
1716
|
+
};
|
|
1717
|
+
}
|
|
1718
|
+
if (this.check([79, 84, 84, 79, 0])) {
|
|
1719
|
+
return {
|
|
1720
|
+
ext: "otf",
|
|
1721
|
+
mime: "font/otf"
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
if (this.checkString("#!AMR")) {
|
|
1725
|
+
return {
|
|
1726
|
+
ext: "amr",
|
|
1727
|
+
mime: "audio/amr"
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1730
|
+
if (this.checkString("{\\rtf")) {
|
|
1731
|
+
return {
|
|
1732
|
+
ext: "rtf",
|
|
1733
|
+
mime: "application/rtf"
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
if (this.check([70, 76, 86, 1])) {
|
|
1737
|
+
return {
|
|
1738
|
+
ext: "flv",
|
|
1739
|
+
mime: "video/x-flv"
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
if (this.checkString("IMPM")) {
|
|
1743
|
+
return {
|
|
1744
|
+
ext: "it",
|
|
1745
|
+
mime: "audio/x-it"
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
if (this.checkString("-lh0-", { offset: 2 }) || this.checkString("-lh1-", { offset: 2 }) || this.checkString("-lh2-", { offset: 2 }) || this.checkString("-lh3-", { offset: 2 }) || this.checkString("-lh4-", { offset: 2 }) || this.checkString("-lh5-", { offset: 2 }) || this.checkString("-lh6-", { offset: 2 }) || this.checkString("-lh7-", { offset: 2 }) || this.checkString("-lzs-", { offset: 2 }) || this.checkString("-lz4-", { offset: 2 }) || this.checkString("-lz5-", { offset: 2 }) || this.checkString("-lhd-", { offset: 2 })) {
|
|
1749
|
+
return {
|
|
1750
|
+
ext: "lzh",
|
|
1751
|
+
mime: "application/x-lzh-compressed"
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
if (this.check([0, 0, 1, 186])) {
|
|
1755
|
+
if (this.check([33], { offset: 4, mask: [241] })) {
|
|
1756
|
+
return {
|
|
1757
|
+
ext: "mpg",
|
|
1758
|
+
// May also be .ps, .mpeg
|
|
1759
|
+
mime: "video/MP1S"
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
if (this.check([68], { offset: 4, mask: [196] })) {
|
|
1763
|
+
return {
|
|
1764
|
+
ext: "mpg",
|
|
1765
|
+
// May also be .mpg, .m2p, .vob or .sub
|
|
1766
|
+
mime: "video/MP2P"
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
if (this.checkString("ITSF")) {
|
|
1771
|
+
return {
|
|
1772
|
+
ext: "chm",
|
|
1773
|
+
mime: "application/vnd.ms-htmlhelp"
|
|
1774
|
+
};
|
|
1775
|
+
}
|
|
1776
|
+
if (this.check([202, 254, 186, 190])) {
|
|
1777
|
+
const machOArchitectureCount = UINT32_BE.get(this.buffer, 4);
|
|
1778
|
+
const javaClassFileMajorVersion = UINT16_BE.get(this.buffer, 6);
|
|
1779
|
+
if (machOArchitectureCount > 0 && machOArchitectureCount <= 30) {
|
|
1780
|
+
return {
|
|
1781
|
+
ext: "macho",
|
|
1782
|
+
mime: "application/x-mach-binary"
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
if (javaClassFileMajorVersion > 30) {
|
|
1786
|
+
return {
|
|
1787
|
+
ext: "class",
|
|
1788
|
+
mime: "application/java-vm"
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
if (this.checkString(".RMF")) {
|
|
1793
|
+
return {
|
|
1794
|
+
ext: "rm",
|
|
1795
|
+
mime: "application/vnd.rn-realmedia"
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
if (this.checkString("DRACO")) {
|
|
1799
|
+
return {
|
|
1800
|
+
ext: "drc",
|
|
1801
|
+
mime: "application/vnd.google.draco"
|
|
1802
|
+
// Invented by us
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
if (this.check([253, 55, 122, 88, 90, 0])) {
|
|
1806
|
+
return {
|
|
1807
|
+
ext: "xz",
|
|
1808
|
+
mime: "application/x-xz"
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
if (this.checkString("<?xml ")) {
|
|
1812
|
+
return {
|
|
1813
|
+
ext: "xml",
|
|
1814
|
+
mime: "application/xml"
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
if (this.check([55, 122, 188, 175, 39, 28])) {
|
|
1818
|
+
return {
|
|
1819
|
+
ext: "7z",
|
|
1820
|
+
mime: "application/x-7z-compressed"
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1823
|
+
if (this.check([82, 97, 114, 33, 26, 7]) && (this.buffer[6] === 0 || this.buffer[6] === 1)) {
|
|
1824
|
+
return {
|
|
1825
|
+
ext: "rar",
|
|
1826
|
+
mime: "application/x-rar-compressed"
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1829
|
+
if (this.checkString("solid ")) {
|
|
1830
|
+
return {
|
|
1831
|
+
ext: "stl",
|
|
1832
|
+
mime: "model/stl"
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
if (this.checkString("AC")) {
|
|
1836
|
+
const version = new StringType(4, "latin1").get(this.buffer, 2);
|
|
1837
|
+
if (version.match("^d*") && version >= 1e3 && version <= 1050) {
|
|
1838
|
+
return {
|
|
1839
|
+
ext: "dwg",
|
|
1840
|
+
mime: "image/vnd.dwg"
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
if (this.checkString("070707")) {
|
|
1845
|
+
return {
|
|
1846
|
+
ext: "cpio",
|
|
1847
|
+
mime: "application/x-cpio"
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
if (this.checkString("BLENDER")) {
|
|
1851
|
+
return {
|
|
1852
|
+
ext: "blend",
|
|
1853
|
+
mime: "application/x-blender"
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
if (this.checkString("!<arch>")) {
|
|
1857
|
+
await tokenizer.ignore(8);
|
|
1858
|
+
const string = await tokenizer.readToken(new StringType(13, "ascii"));
|
|
1859
|
+
if (string === "debian-binary") {
|
|
1860
|
+
return {
|
|
1861
|
+
ext: "deb",
|
|
1862
|
+
mime: "application/x-deb"
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1865
|
+
return {
|
|
1866
|
+
ext: "ar",
|
|
1867
|
+
mime: "application/x-unix-archive"
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
if (this.checkString("WEBVTT") && // One of LF, CR, tab, space, or end of file must follow "WEBVTT" per the spec (see `fixture/fixture-vtt-*.vtt` for examples). Note that `\0` is technically the null character (there is no such thing as an EOF character). However, checking for `\0` gives us the same result as checking for the end of the stream.
|
|
1871
|
+
["\n", "\r", " ", " ", "\0"].some((char7) => this.checkString(char7, { offset: 6 }))) {
|
|
1872
|
+
return {
|
|
1873
|
+
ext: "vtt",
|
|
1874
|
+
mime: "text/vtt"
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
if (this.check([137, 80, 78, 71, 13, 10, 26, 10])) {
|
|
1878
|
+
await tokenizer.ignore(8);
|
|
1879
|
+
async function readChunkHeader() {
|
|
1880
|
+
return {
|
|
1881
|
+
length: await tokenizer.readToken(INT32_BE),
|
|
1882
|
+
type: await tokenizer.readToken(new StringType(4, "latin1"))
|
|
1883
|
+
};
|
|
1884
|
+
}
|
|
1885
|
+
do {
|
|
1886
|
+
const chunk = await readChunkHeader();
|
|
1887
|
+
if (chunk.length < 0) {
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
switch (chunk.type) {
|
|
1891
|
+
case "IDAT":
|
|
1892
|
+
return {
|
|
1893
|
+
ext: "png",
|
|
1894
|
+
mime: "image/png"
|
|
1895
|
+
};
|
|
1896
|
+
case "acTL":
|
|
1897
|
+
return {
|
|
1898
|
+
ext: "apng",
|
|
1899
|
+
mime: "image/apng"
|
|
1900
|
+
};
|
|
1901
|
+
default:
|
|
1902
|
+
await tokenizer.ignore(chunk.length + 4);
|
|
1903
|
+
}
|
|
1904
|
+
} while (tokenizer.position + 8 < tokenizer.fileInfo.size);
|
|
1905
|
+
return {
|
|
1906
|
+
ext: "png",
|
|
1907
|
+
mime: "image/png"
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
if (this.check([65, 82, 82, 79, 87, 49, 0, 0])) {
|
|
1911
|
+
return {
|
|
1912
|
+
ext: "arrow",
|
|
1913
|
+
mime: "application/vnd.apache.arrow.file"
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
if (this.check([103, 108, 84, 70, 2, 0, 0, 0])) {
|
|
1917
|
+
return {
|
|
1918
|
+
ext: "glb",
|
|
1919
|
+
mime: "model/gltf-binary"
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
if (this.check([102, 114, 101, 101], { offset: 4 }) || this.check([109, 100, 97, 116], { offset: 4 }) || this.check([109, 111, 111, 118], { offset: 4 }) || this.check([119, 105, 100, 101], { offset: 4 })) {
|
|
1923
|
+
return {
|
|
1924
|
+
ext: "mov",
|
|
1925
|
+
mime: "video/quicktime"
|
|
1926
|
+
};
|
|
1927
|
+
}
|
|
1928
|
+
if (this.check([73, 73, 82, 79, 8, 0, 0, 0, 24])) {
|
|
1929
|
+
return {
|
|
1930
|
+
ext: "orf",
|
|
1931
|
+
mime: "image/x-olympus-orf"
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
if (this.checkString("gimp xcf ")) {
|
|
1935
|
+
return {
|
|
1936
|
+
ext: "xcf",
|
|
1937
|
+
mime: "image/x-xcf"
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
if (this.checkString("ftyp", { offset: 4 }) && (this.buffer[8] & 96) !== 0) {
|
|
1941
|
+
const brandMajor = new StringType(4, "latin1").get(this.buffer, 8).replace("\0", " ").trim();
|
|
1942
|
+
switch (brandMajor) {
|
|
1943
|
+
case "avif":
|
|
1944
|
+
case "avis":
|
|
1945
|
+
return { ext: "avif", mime: "image/avif" };
|
|
1946
|
+
case "mif1":
|
|
1947
|
+
return { ext: "heic", mime: "image/heif" };
|
|
1948
|
+
case "msf1":
|
|
1949
|
+
return { ext: "heic", mime: "image/heif-sequence" };
|
|
1950
|
+
case "heic":
|
|
1951
|
+
case "heix":
|
|
1952
|
+
return { ext: "heic", mime: "image/heic" };
|
|
1953
|
+
case "hevc":
|
|
1954
|
+
case "hevx":
|
|
1955
|
+
return { ext: "heic", mime: "image/heic-sequence" };
|
|
1956
|
+
case "qt":
|
|
1957
|
+
return { ext: "mov", mime: "video/quicktime" };
|
|
1958
|
+
case "M4V":
|
|
1959
|
+
case "M4VH":
|
|
1960
|
+
case "M4VP":
|
|
1961
|
+
return { ext: "m4v", mime: "video/x-m4v" };
|
|
1962
|
+
case "M4P":
|
|
1963
|
+
return { ext: "m4p", mime: "video/mp4" };
|
|
1964
|
+
case "M4B":
|
|
1965
|
+
return { ext: "m4b", mime: "audio/mp4" };
|
|
1966
|
+
case "M4A":
|
|
1967
|
+
return { ext: "m4a", mime: "audio/x-m4a" };
|
|
1968
|
+
case "F4V":
|
|
1969
|
+
return { ext: "f4v", mime: "video/mp4" };
|
|
1970
|
+
case "F4P":
|
|
1971
|
+
return { ext: "f4p", mime: "video/mp4" };
|
|
1972
|
+
case "F4A":
|
|
1973
|
+
return { ext: "f4a", mime: "audio/mp4" };
|
|
1974
|
+
case "F4B":
|
|
1975
|
+
return { ext: "f4b", mime: "audio/mp4" };
|
|
1976
|
+
case "crx":
|
|
1977
|
+
return { ext: "cr3", mime: "image/x-canon-cr3" };
|
|
1978
|
+
default:
|
|
1979
|
+
if (brandMajor.startsWith("3g")) {
|
|
1980
|
+
if (brandMajor.startsWith("3g2")) {
|
|
1981
|
+
return { ext: "3g2", mime: "video/3gpp2" };
|
|
1982
|
+
}
|
|
1983
|
+
return { ext: "3gp", mime: "video/3gpp" };
|
|
1984
|
+
}
|
|
1985
|
+
return { ext: "mp4", mime: "video/mp4" };
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
if (this.checkString("REGEDIT4\r\n")) {
|
|
1989
|
+
return {
|
|
1990
|
+
ext: "reg",
|
|
1991
|
+
mime: "application/x-ms-regedit"
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
if (this.check([82, 73, 70, 70])) {
|
|
1995
|
+
if (this.checkString("WEBP", { offset: 8 })) {
|
|
1996
|
+
return {
|
|
1997
|
+
ext: "webp",
|
|
1998
|
+
mime: "image/webp"
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
if (this.check([65, 86, 73], { offset: 8 })) {
|
|
2002
|
+
return {
|
|
2003
|
+
ext: "avi",
|
|
2004
|
+
mime: "video/vnd.avi"
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
if (this.check([87, 65, 86, 69], { offset: 8 })) {
|
|
2008
|
+
return {
|
|
2009
|
+
ext: "wav",
|
|
2010
|
+
mime: "audio/wav"
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2013
|
+
if (this.check([81, 76, 67, 77], { offset: 8 })) {
|
|
2014
|
+
return {
|
|
2015
|
+
ext: "qcp",
|
|
2016
|
+
mime: "audio/qcelp"
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
if (this.check([73, 73, 85, 0, 24, 0, 0, 0, 136, 231, 116, 216])) {
|
|
2021
|
+
return {
|
|
2022
|
+
ext: "rw2",
|
|
2023
|
+
mime: "image/x-panasonic-rw2"
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
if (this.check([48, 38, 178, 117, 142, 102, 207, 17, 166, 217])) {
|
|
2027
|
+
async function readHeader() {
|
|
2028
|
+
const guid = new Uint8Array(16);
|
|
2029
|
+
await tokenizer.readBuffer(guid);
|
|
2030
|
+
return {
|
|
2031
|
+
id: guid,
|
|
2032
|
+
size: Number(await tokenizer.readToken(UINT64_LE))
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
await tokenizer.ignore(30);
|
|
2036
|
+
while (tokenizer.position + 24 < tokenizer.fileInfo.size) {
|
|
2037
|
+
const header = await readHeader();
|
|
2038
|
+
let payload = header.size - 24;
|
|
2039
|
+
if (_check(header.id, [145, 7, 220, 183, 183, 169, 207, 17, 142, 230, 0, 192, 12, 32, 83, 101])) {
|
|
2040
|
+
const typeId = new Uint8Array(16);
|
|
2041
|
+
payload -= await tokenizer.readBuffer(typeId);
|
|
2042
|
+
if (_check(typeId, [64, 158, 105, 248, 77, 91, 207, 17, 168, 253, 0, 128, 95, 92, 68, 43])) {
|
|
2043
|
+
return {
|
|
2044
|
+
ext: "asf",
|
|
2045
|
+
mime: "audio/x-ms-asf"
|
|
2046
|
+
};
|
|
2047
|
+
}
|
|
2048
|
+
if (_check(typeId, [192, 239, 25, 188, 77, 91, 207, 17, 168, 253, 0, 128, 95, 92, 68, 43])) {
|
|
2049
|
+
return {
|
|
2050
|
+
ext: "asf",
|
|
2051
|
+
mime: "video/x-ms-asf"
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
break;
|
|
2055
|
+
}
|
|
2056
|
+
await tokenizer.ignore(payload);
|
|
2057
|
+
}
|
|
2058
|
+
return {
|
|
2059
|
+
ext: "asf",
|
|
2060
|
+
mime: "application/vnd.ms-asf"
|
|
2061
|
+
};
|
|
2062
|
+
}
|
|
2063
|
+
if (this.check([171, 75, 84, 88, 32, 49, 49, 187, 13, 10, 26, 10])) {
|
|
2064
|
+
return {
|
|
2065
|
+
ext: "ktx",
|
|
2066
|
+
mime: "image/ktx"
|
|
2067
|
+
};
|
|
2068
|
+
}
|
|
2069
|
+
if ((this.check([126, 16, 4]) || this.check([126, 24, 4])) && this.check([48, 77, 73, 69], { offset: 4 })) {
|
|
2070
|
+
return {
|
|
2071
|
+
ext: "mie",
|
|
2072
|
+
mime: "application/x-mie"
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
if (this.check([39, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], { offset: 2 })) {
|
|
2076
|
+
return {
|
|
2077
|
+
ext: "shp",
|
|
2078
|
+
mime: "application/x-esri-shape"
|
|
2079
|
+
};
|
|
2080
|
+
}
|
|
2081
|
+
if (this.check([255, 79, 255, 81])) {
|
|
2082
|
+
return {
|
|
2083
|
+
ext: "j2c",
|
|
2084
|
+
mime: "image/j2c"
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
if (this.check([0, 0, 0, 12, 106, 80, 32, 32, 13, 10, 135, 10])) {
|
|
2088
|
+
await tokenizer.ignore(20);
|
|
2089
|
+
const type = await tokenizer.readToken(new StringType(4, "ascii"));
|
|
2090
|
+
switch (type) {
|
|
2091
|
+
case "jp2 ":
|
|
2092
|
+
return {
|
|
2093
|
+
ext: "jp2",
|
|
2094
|
+
mime: "image/jp2"
|
|
2095
|
+
};
|
|
2096
|
+
case "jpx ":
|
|
2097
|
+
return {
|
|
2098
|
+
ext: "jpx",
|
|
2099
|
+
mime: "image/jpx"
|
|
2100
|
+
};
|
|
2101
|
+
case "jpm ":
|
|
2102
|
+
return {
|
|
2103
|
+
ext: "jpm",
|
|
2104
|
+
mime: "image/jpm"
|
|
2105
|
+
};
|
|
2106
|
+
case "mjp2":
|
|
2107
|
+
return {
|
|
2108
|
+
ext: "mj2",
|
|
2109
|
+
mime: "image/mj2"
|
|
2110
|
+
};
|
|
2111
|
+
default:
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
if (this.check([255, 10]) || this.check([0, 0, 0, 12, 74, 88, 76, 32, 13, 10, 135, 10])) {
|
|
2116
|
+
return {
|
|
2117
|
+
ext: "jxl",
|
|
2118
|
+
mime: "image/jxl"
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
2121
|
+
if (this.check([254, 255])) {
|
|
2122
|
+
if (this.checkString("<?xml ", { offset: 2, encoding: "utf-16be" })) {
|
|
2123
|
+
return {
|
|
2124
|
+
ext: "xml",
|
|
2125
|
+
mime: "application/xml"
|
|
2126
|
+
};
|
|
2127
|
+
}
|
|
2128
|
+
return void 0;
|
|
2129
|
+
}
|
|
2130
|
+
if (this.check([208, 207, 17, 224, 161, 177, 26, 225])) {
|
|
2131
|
+
return {
|
|
2132
|
+
ext: "cfb",
|
|
2133
|
+
mime: "application/x-cfb"
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
await tokenizer.peekBuffer(this.buffer, { length: Math.min(256, tokenizer.fileInfo.size), mayBeLess: true });
|
|
2137
|
+
if (this.check([97, 99, 115, 112], { offset: 36 })) {
|
|
2138
|
+
return {
|
|
2139
|
+
ext: "icc",
|
|
2140
|
+
mime: "application/vnd.iccprofile"
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
if (this.checkString("**ACE", { offset: 7 }) && this.checkString("**", { offset: 12 })) {
|
|
2144
|
+
return {
|
|
2145
|
+
ext: "ace",
|
|
2146
|
+
mime: "application/x-ace-compressed"
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
if (this.checkString("BEGIN:")) {
|
|
2150
|
+
if (this.checkString("VCARD", { offset: 6 })) {
|
|
2151
|
+
return {
|
|
2152
|
+
ext: "vcf",
|
|
2153
|
+
mime: "text/vcard"
|
|
2154
|
+
};
|
|
2155
|
+
}
|
|
2156
|
+
if (this.checkString("VCALENDAR", { offset: 6 })) {
|
|
2157
|
+
return {
|
|
2158
|
+
ext: "ics",
|
|
2159
|
+
mime: "text/calendar"
|
|
2160
|
+
};
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
if (this.checkString("FUJIFILMCCD-RAW")) {
|
|
2164
|
+
return {
|
|
2165
|
+
ext: "raf",
|
|
2166
|
+
mime: "image/x-fujifilm-raf"
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
if (this.checkString("Extended Module:")) {
|
|
2170
|
+
return {
|
|
2171
|
+
ext: "xm",
|
|
2172
|
+
mime: "audio/x-xm"
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
if (this.checkString("Creative Voice File")) {
|
|
2176
|
+
return {
|
|
2177
|
+
ext: "voc",
|
|
2178
|
+
mime: "audio/x-voc"
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
if (this.check([4, 0, 0, 0]) && this.buffer.length >= 16) {
|
|
2182
|
+
const jsonSize = new DataView(this.buffer.buffer).getUint32(12, true);
|
|
2183
|
+
if (jsonSize > 12 && this.buffer.length >= jsonSize + 16) {
|
|
2184
|
+
try {
|
|
2185
|
+
const header = new TextDecoder().decode(this.buffer.subarray(16, jsonSize + 16));
|
|
2186
|
+
const json = JSON.parse(header);
|
|
2187
|
+
if (json.files) {
|
|
2188
|
+
return {
|
|
2189
|
+
ext: "asar",
|
|
2190
|
+
mime: "application/x-asar"
|
|
2191
|
+
};
|
|
2192
|
+
}
|
|
2193
|
+
} catch {
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
if (this.check([6, 14, 43, 52, 2, 5, 1, 1, 13, 1, 2, 1, 1, 2])) {
|
|
2198
|
+
return {
|
|
2199
|
+
ext: "mxf",
|
|
2200
|
+
mime: "application/mxf"
|
|
2201
|
+
};
|
|
2202
|
+
}
|
|
2203
|
+
if (this.checkString("SCRM", { offset: 44 })) {
|
|
2204
|
+
return {
|
|
2205
|
+
ext: "s3m",
|
|
2206
|
+
mime: "audio/x-s3m"
|
|
2207
|
+
};
|
|
2208
|
+
}
|
|
2209
|
+
if (this.check([71]) && this.check([71], { offset: 188 })) {
|
|
2210
|
+
return {
|
|
2211
|
+
ext: "mts",
|
|
2212
|
+
mime: "video/mp2t"
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
if (this.check([71], { offset: 4 }) && this.check([71], { offset: 196 })) {
|
|
2216
|
+
return {
|
|
2217
|
+
ext: "mts",
|
|
2218
|
+
mime: "video/mp2t"
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
if (this.check([66, 79, 79, 75, 77, 79, 66, 73], { offset: 60 })) {
|
|
2222
|
+
return {
|
|
2223
|
+
ext: "mobi",
|
|
2224
|
+
mime: "application/x-mobipocket-ebook"
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
if (this.check([68, 73, 67, 77], { offset: 128 })) {
|
|
2228
|
+
return {
|
|
2229
|
+
ext: "dcm",
|
|
2230
|
+
mime: "application/dicom"
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
if (this.check([76, 0, 0, 0, 1, 20, 2, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 70])) {
|
|
2234
|
+
return {
|
|
2235
|
+
ext: "lnk",
|
|
2236
|
+
mime: "application/x.ms.shortcut"
|
|
2237
|
+
// Invented by us
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
if (this.check([98, 111, 111, 107, 0, 0, 0, 0, 109, 97, 114, 107, 0, 0, 0, 0])) {
|
|
2241
|
+
return {
|
|
2242
|
+
ext: "alias",
|
|
2243
|
+
mime: "application/x.apple.alias"
|
|
2244
|
+
// Invented by us
|
|
2245
|
+
};
|
|
2246
|
+
}
|
|
2247
|
+
if (this.checkString("Kaydara FBX Binary \0")) {
|
|
2248
|
+
return {
|
|
2249
|
+
ext: "fbx",
|
|
2250
|
+
mime: "application/x.autodesk.fbx"
|
|
2251
|
+
// Invented by us
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2254
|
+
if (this.check([76, 80], { offset: 34 }) && (this.check([0, 0, 1], { offset: 8 }) || this.check([1, 0, 2], { offset: 8 }) || this.check([2, 0, 2], { offset: 8 }))) {
|
|
2255
|
+
return {
|
|
2256
|
+
ext: "eot",
|
|
2257
|
+
mime: "application/vnd.ms-fontobject"
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
if (this.check([6, 6, 237, 245, 216, 29, 70, 229, 189, 49, 239, 231, 254, 116, 183, 29])) {
|
|
2261
|
+
return {
|
|
2262
|
+
ext: "indd",
|
|
2263
|
+
mime: "application/x-indesign"
|
|
2264
|
+
};
|
|
2265
|
+
}
|
|
2266
|
+
if (this.check([255, 255, 0, 0, 7, 0, 0, 0, 4, 0, 0, 0, 1, 0, 1, 0]) || this.check([0, 0, 255, 255, 0, 0, 0, 7, 0, 0, 0, 4, 0, 1, 0, 1])) {
|
|
2267
|
+
return {
|
|
2268
|
+
ext: "jmp",
|
|
2269
|
+
mime: "application/x-jmp-data"
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
await tokenizer.peekBuffer(this.buffer, { length: Math.min(512, tokenizer.fileInfo.size), mayBeLess: true });
|
|
2273
|
+
if (this.checkString("ustar", { offset: 257 }) && (this.checkString("\0", { offset: 262 }) || this.checkString(" ", { offset: 262 })) || this.check([0, 0, 0, 0, 0, 0], { offset: 257 }) && tarHeaderChecksumMatches(this.buffer)) {
|
|
2274
|
+
return {
|
|
2275
|
+
ext: "tar",
|
|
2276
|
+
mime: "application/x-tar"
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
if (this.check([255, 254])) {
|
|
2280
|
+
const encoding = "utf-16le";
|
|
2281
|
+
if (this.checkString("<?xml ", { offset: 2, encoding })) {
|
|
2282
|
+
return {
|
|
2283
|
+
ext: "xml",
|
|
2284
|
+
mime: "application/xml"
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
if (this.check([255, 14], { offset: 2 }) && this.checkString("SketchUp Model", { offset: 4, encoding })) {
|
|
2288
|
+
return {
|
|
2289
|
+
ext: "skp",
|
|
2290
|
+
mime: "application/vnd.sketchup.skp"
|
|
2291
|
+
};
|
|
2292
|
+
}
|
|
2293
|
+
if (this.checkString("Windows Registry Editor Version 5.00\r\n", { offset: 2, encoding })) {
|
|
2294
|
+
return {
|
|
2295
|
+
ext: "reg",
|
|
2296
|
+
mime: "application/x-ms-regedit"
|
|
2297
|
+
};
|
|
2298
|
+
}
|
|
2299
|
+
return void 0;
|
|
2300
|
+
}
|
|
2301
|
+
if (this.checkString("-----BEGIN PGP MESSAGE-----")) {
|
|
2302
|
+
return {
|
|
2303
|
+
ext: "pgp",
|
|
2304
|
+
mime: "application/pgp-encrypted"
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
};
|
|
2308
|
+
// Detections with limited supporting data, resulting in a higher likelihood of false positives
|
|
2309
|
+
detectImprecise = async (tokenizer) => {
|
|
2310
|
+
this.buffer = new Uint8Array(reasonableDetectionSizeInBytes);
|
|
2311
|
+
await tokenizer.peekBuffer(this.buffer, { length: Math.min(8, tokenizer.fileInfo.size), mayBeLess: true });
|
|
2312
|
+
if (this.check([0, 0, 1, 186]) || this.check([0, 0, 1, 179])) {
|
|
2313
|
+
return {
|
|
2314
|
+
ext: "mpg",
|
|
2315
|
+
mime: "video/mpeg"
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
if (this.check([0, 1, 0, 0, 0])) {
|
|
2319
|
+
return {
|
|
2320
|
+
ext: "ttf",
|
|
2321
|
+
mime: "font/ttf"
|
|
2322
|
+
};
|
|
2323
|
+
}
|
|
2324
|
+
if (this.check([0, 0, 1, 0])) {
|
|
2325
|
+
return {
|
|
2326
|
+
ext: "ico",
|
|
2327
|
+
mime: "image/x-icon"
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
if (this.check([0, 0, 2, 0])) {
|
|
2331
|
+
return {
|
|
2332
|
+
ext: "cur",
|
|
2333
|
+
mime: "image/x-icon"
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
await tokenizer.peekBuffer(this.buffer, { length: Math.min(2 + this.options.mpegOffsetTolerance, tokenizer.fileInfo.size), mayBeLess: true });
|
|
2337
|
+
if (this.buffer.length >= 2 + this.options.mpegOffsetTolerance) {
|
|
2338
|
+
for (let depth = 0; depth <= this.options.mpegOffsetTolerance; ++depth) {
|
|
2339
|
+
const type = this.scanMpeg(depth);
|
|
2340
|
+
if (type) {
|
|
2341
|
+
return type;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
};
|
|
2346
|
+
async readTiffTag(bigEndian) {
|
|
2347
|
+
const tagId = await this.tokenizer.readToken(bigEndian ? UINT16_BE : UINT16_LE);
|
|
2348
|
+
this.tokenizer.ignore(10);
|
|
2349
|
+
switch (tagId) {
|
|
2350
|
+
case 50341:
|
|
2351
|
+
return {
|
|
2352
|
+
ext: "arw",
|
|
2353
|
+
mime: "image/x-sony-arw"
|
|
2354
|
+
};
|
|
2355
|
+
case 50706:
|
|
2356
|
+
return {
|
|
2357
|
+
ext: "dng",
|
|
2358
|
+
mime: "image/x-adobe-dng"
|
|
2359
|
+
};
|
|
2360
|
+
default:
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
async readTiffIFD(bigEndian) {
|
|
2364
|
+
const numberOfTags = await this.tokenizer.readToken(bigEndian ? UINT16_BE : UINT16_LE);
|
|
2365
|
+
for (let n = 0; n < numberOfTags; ++n) {
|
|
2366
|
+
const fileType = await this.readTiffTag(bigEndian);
|
|
2367
|
+
if (fileType) {
|
|
2368
|
+
return fileType;
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
async readTiffHeader(bigEndian) {
|
|
2373
|
+
const version = (bigEndian ? UINT16_BE : UINT16_LE).get(this.buffer, 2);
|
|
2374
|
+
const ifdOffset = (bigEndian ? UINT32_BE : UINT32_LE).get(this.buffer, 4);
|
|
2375
|
+
if (version === 42) {
|
|
2376
|
+
if (ifdOffset >= 6) {
|
|
2377
|
+
if (this.checkString("CR", { offset: 8 })) {
|
|
2378
|
+
return {
|
|
2379
|
+
ext: "cr2",
|
|
2380
|
+
mime: "image/x-canon-cr2"
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
if (ifdOffset >= 8) {
|
|
2384
|
+
const someId1 = (bigEndian ? UINT16_BE : UINT16_LE).get(this.buffer, 8);
|
|
2385
|
+
const someId2 = (bigEndian ? UINT16_BE : UINT16_LE).get(this.buffer, 10);
|
|
2386
|
+
if (someId1 === 28 && someId2 === 254 || someId1 === 31 && someId2 === 11) {
|
|
2387
|
+
return {
|
|
2388
|
+
ext: "nef",
|
|
2389
|
+
mime: "image/x-nikon-nef"
|
|
2390
|
+
};
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
await this.tokenizer.ignore(ifdOffset);
|
|
2395
|
+
const fileType = await this.readTiffIFD(bigEndian);
|
|
2396
|
+
return fileType ?? {
|
|
2397
|
+
ext: "tif",
|
|
2398
|
+
mime: "image/tiff"
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
if (version === 43) {
|
|
2402
|
+
return {
|
|
2403
|
+
ext: "tif",
|
|
2404
|
+
mime: "image/tiff"
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2409
|
+
Scan check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE).
|
|
2410
|
+
|
|
2411
|
+
@param offset - Offset to scan for sync-preamble.
|
|
2412
|
+
@returns {{ext: string, mime: string}}
|
|
2413
|
+
*/
|
|
2414
|
+
scanMpeg(offset) {
|
|
2415
|
+
if (this.check([255, 224], { offset, mask: [255, 224] })) {
|
|
2416
|
+
if (this.check([16], { offset: offset + 1, mask: [22] })) {
|
|
2417
|
+
if (this.check([8], { offset: offset + 1, mask: [8] })) {
|
|
2418
|
+
return {
|
|
2419
|
+
ext: "aac",
|
|
2420
|
+
mime: "audio/aac"
|
|
2421
|
+
};
|
|
2422
|
+
}
|
|
2423
|
+
return {
|
|
2424
|
+
ext: "aac",
|
|
2425
|
+
mime: "audio/aac"
|
|
2426
|
+
};
|
|
2427
|
+
}
|
|
2428
|
+
if (this.check([2], { offset: offset + 1, mask: [6] })) {
|
|
2429
|
+
return {
|
|
2430
|
+
ext: "mp3",
|
|
2431
|
+
mime: "audio/mpeg"
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2434
|
+
if (this.check([4], { offset: offset + 1, mask: [6] })) {
|
|
2435
|
+
return {
|
|
2436
|
+
ext: "mp2",
|
|
2437
|
+
mime: "audio/mpeg"
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
if (this.check([6], { offset: offset + 1, mask: [6] })) {
|
|
2441
|
+
return {
|
|
2442
|
+
ext: "mp1",
|
|
2443
|
+
mime: "audio/mpeg"
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
};
|
|
2449
|
+
var supportedExtensions = new Set(extensions);
|
|
2450
|
+
var supportedMimeTypes = new Set(mimeTypes);
|
|
2451
|
+
|
|
2452
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/ParserFactory.js
|
|
2453
|
+
var import_content_type = __toESM(require_content_type(), 1);
|
|
2454
|
+
var import_media_typer = __toESM(require_media_typer(), 1);
|
|
2455
|
+
var import_debug3 = __toESM(require_src(), 1);
|
|
2456
|
+
|
|
2457
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/common/MetadataCollector.js
|
|
2458
|
+
var import_debug2 = __toESM(require_src(), 1);
|
|
2459
|
+
|
|
2460
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/common/GenericTagTypes.js
|
|
2461
|
+
var defaultTagInfo = {
|
|
2462
|
+
multiple: false
|
|
2463
|
+
};
|
|
2464
|
+
var commonTags = {
|
|
2465
|
+
year: defaultTagInfo,
|
|
2466
|
+
track: defaultTagInfo,
|
|
2467
|
+
disk: defaultTagInfo,
|
|
2468
|
+
title: defaultTagInfo,
|
|
2469
|
+
artist: defaultTagInfo,
|
|
2470
|
+
artists: { multiple: true, unique: true },
|
|
2471
|
+
albumartist: defaultTagInfo,
|
|
2472
|
+
albumartists: { multiple: true, unique: true },
|
|
2473
|
+
album: defaultTagInfo,
|
|
2474
|
+
date: defaultTagInfo,
|
|
2475
|
+
originaldate: defaultTagInfo,
|
|
2476
|
+
originalyear: defaultTagInfo,
|
|
2477
|
+
releasedate: defaultTagInfo,
|
|
2478
|
+
comment: { multiple: true, unique: false },
|
|
2479
|
+
genre: { multiple: true, unique: true },
|
|
2480
|
+
picture: { multiple: true, unique: true },
|
|
2481
|
+
composer: { multiple: true, unique: true },
|
|
2482
|
+
lyrics: { multiple: true, unique: false },
|
|
2483
|
+
albumsort: { multiple: false, unique: true },
|
|
2484
|
+
titlesort: { multiple: false, unique: true },
|
|
2485
|
+
work: { multiple: false, unique: true },
|
|
2486
|
+
artistsort: { multiple: false, unique: true },
|
|
2487
|
+
albumartistsort: { multiple: false, unique: true },
|
|
2488
|
+
composersort: { multiple: false, unique: true },
|
|
2489
|
+
lyricist: { multiple: true, unique: true },
|
|
2490
|
+
writer: { multiple: true, unique: true },
|
|
2491
|
+
conductor: { multiple: true, unique: true },
|
|
2492
|
+
remixer: { multiple: true, unique: true },
|
|
2493
|
+
arranger: { multiple: true, unique: true },
|
|
2494
|
+
engineer: { multiple: true, unique: true },
|
|
2495
|
+
producer: { multiple: true, unique: true },
|
|
2496
|
+
technician: { multiple: true, unique: true },
|
|
2497
|
+
djmixer: { multiple: true, unique: true },
|
|
2498
|
+
mixer: { multiple: true, unique: true },
|
|
2499
|
+
label: { multiple: true, unique: true },
|
|
2500
|
+
grouping: defaultTagInfo,
|
|
2501
|
+
subtitle: { multiple: true },
|
|
2502
|
+
discsubtitle: defaultTagInfo,
|
|
2503
|
+
totaltracks: defaultTagInfo,
|
|
2504
|
+
totaldiscs: defaultTagInfo,
|
|
2505
|
+
compilation: defaultTagInfo,
|
|
2506
|
+
rating: { multiple: true },
|
|
2507
|
+
bpm: defaultTagInfo,
|
|
2508
|
+
mood: defaultTagInfo,
|
|
2509
|
+
media: defaultTagInfo,
|
|
2510
|
+
catalognumber: { multiple: true, unique: true },
|
|
2511
|
+
tvShow: defaultTagInfo,
|
|
2512
|
+
tvShowSort: defaultTagInfo,
|
|
2513
|
+
tvSeason: defaultTagInfo,
|
|
2514
|
+
tvEpisode: defaultTagInfo,
|
|
2515
|
+
tvEpisodeId: defaultTagInfo,
|
|
2516
|
+
tvNetwork: defaultTagInfo,
|
|
2517
|
+
podcast: defaultTagInfo,
|
|
2518
|
+
podcasturl: defaultTagInfo,
|
|
2519
|
+
releasestatus: defaultTagInfo,
|
|
2520
|
+
releasetype: { multiple: true },
|
|
2521
|
+
releasecountry: defaultTagInfo,
|
|
2522
|
+
script: defaultTagInfo,
|
|
2523
|
+
language: defaultTagInfo,
|
|
2524
|
+
copyright: defaultTagInfo,
|
|
2525
|
+
license: defaultTagInfo,
|
|
2526
|
+
encodedby: defaultTagInfo,
|
|
2527
|
+
encodersettings: defaultTagInfo,
|
|
2528
|
+
gapless: defaultTagInfo,
|
|
2529
|
+
barcode: defaultTagInfo,
|
|
2530
|
+
isrc: { multiple: true },
|
|
2531
|
+
asin: defaultTagInfo,
|
|
2532
|
+
musicbrainz_recordingid: defaultTagInfo,
|
|
2533
|
+
musicbrainz_trackid: defaultTagInfo,
|
|
2534
|
+
musicbrainz_albumid: defaultTagInfo,
|
|
2535
|
+
musicbrainz_artistid: { multiple: true },
|
|
2536
|
+
musicbrainz_albumartistid: { multiple: true },
|
|
2537
|
+
musicbrainz_releasegroupid: defaultTagInfo,
|
|
2538
|
+
musicbrainz_workid: defaultTagInfo,
|
|
2539
|
+
musicbrainz_trmid: defaultTagInfo,
|
|
2540
|
+
musicbrainz_discid: defaultTagInfo,
|
|
2541
|
+
acoustid_id: defaultTagInfo,
|
|
2542
|
+
acoustid_fingerprint: defaultTagInfo,
|
|
2543
|
+
musicip_puid: defaultTagInfo,
|
|
2544
|
+
musicip_fingerprint: defaultTagInfo,
|
|
2545
|
+
website: defaultTagInfo,
|
|
2546
|
+
"performer:instrument": { multiple: true, unique: true },
|
|
2547
|
+
averageLevel: defaultTagInfo,
|
|
2548
|
+
peakLevel: defaultTagInfo,
|
|
2549
|
+
notes: { multiple: true, unique: false },
|
|
2550
|
+
key: defaultTagInfo,
|
|
2551
|
+
originalalbum: defaultTagInfo,
|
|
2552
|
+
originalartist: defaultTagInfo,
|
|
2553
|
+
discogs_artist_id: { multiple: true, unique: true },
|
|
2554
|
+
discogs_release_id: defaultTagInfo,
|
|
2555
|
+
discogs_label_id: defaultTagInfo,
|
|
2556
|
+
discogs_master_release_id: defaultTagInfo,
|
|
2557
|
+
discogs_votes: defaultTagInfo,
|
|
2558
|
+
discogs_rating: defaultTagInfo,
|
|
2559
|
+
replaygain_track_peak: defaultTagInfo,
|
|
2560
|
+
replaygain_track_gain: defaultTagInfo,
|
|
2561
|
+
replaygain_album_peak: defaultTagInfo,
|
|
2562
|
+
replaygain_album_gain: defaultTagInfo,
|
|
2563
|
+
replaygain_track_minmax: defaultTagInfo,
|
|
2564
|
+
replaygain_album_minmax: defaultTagInfo,
|
|
2565
|
+
replaygain_undo: defaultTagInfo,
|
|
2566
|
+
description: { multiple: true },
|
|
2567
|
+
longDescription: defaultTagInfo,
|
|
2568
|
+
category: { multiple: true },
|
|
2569
|
+
hdVideo: defaultTagInfo,
|
|
2570
|
+
keywords: { multiple: true },
|
|
2571
|
+
movement: defaultTagInfo,
|
|
2572
|
+
movementIndex: defaultTagInfo,
|
|
2573
|
+
movementTotal: defaultTagInfo,
|
|
2574
|
+
podcastId: defaultTagInfo,
|
|
2575
|
+
showMovement: defaultTagInfo,
|
|
2576
|
+
stik: defaultTagInfo,
|
|
2577
|
+
playCounter: defaultTagInfo
|
|
2578
|
+
};
|
|
2579
|
+
function isSingleton(alias) {
|
|
2580
|
+
return commonTags[alias] && !commonTags[alias].multiple;
|
|
2581
|
+
}
|
|
2582
|
+
function isUnique(alias) {
|
|
2583
|
+
return !commonTags[alias].multiple || commonTags[alias].unique || false;
|
|
2584
|
+
}
|
|
2585
|
+
|
|
2586
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/common/GenericTagMapper.js
|
|
2587
|
+
var CommonTagMapper = class {
|
|
2588
|
+
static toIntOrNull(str) {
|
|
2589
|
+
const cleaned = Number.parseInt(str, 10);
|
|
2590
|
+
return Number.isNaN(cleaned) ? null : cleaned;
|
|
2591
|
+
}
|
|
2592
|
+
// TODO: a string of 1of1 would fail to be converted
|
|
2593
|
+
// converts 1/10 to no : 1, of : 10
|
|
2594
|
+
// or 1 to no : 1, of : 0
|
|
2595
|
+
static normalizeTrack(origVal) {
|
|
2596
|
+
const split = origVal.toString().split("/");
|
|
2597
|
+
return {
|
|
2598
|
+
no: Number.parseInt(split[0], 10) || null,
|
|
2599
|
+
of: Number.parseInt(split[1], 10) || null
|
|
2600
|
+
};
|
|
2601
|
+
}
|
|
2602
|
+
constructor(tagTypes, tagMap2) {
|
|
2603
|
+
this.tagTypes = tagTypes;
|
|
2604
|
+
this.tagMap = tagMap2;
|
|
2605
|
+
}
|
|
2606
|
+
/**
|
|
2607
|
+
* Process and set common tags
|
|
2608
|
+
* write common tags to
|
|
2609
|
+
* @param tag Native tag
|
|
2610
|
+
* @param warnings Register warnings
|
|
2611
|
+
* @return common name
|
|
2612
|
+
*/
|
|
2613
|
+
mapGenericTag(tag, warnings) {
|
|
2614
|
+
tag = { id: tag.id, value: tag.value };
|
|
2615
|
+
this.postMap(tag, warnings);
|
|
2616
|
+
const id = this.getCommonName(tag.id);
|
|
2617
|
+
return id ? { id, value: tag.value } : null;
|
|
2618
|
+
}
|
|
2619
|
+
/**
|
|
2620
|
+
* Convert native tag key to common tag key
|
|
2621
|
+
* @param tag Native header tag
|
|
2622
|
+
* @return common tag name (alias)
|
|
2623
|
+
*/
|
|
2624
|
+
getCommonName(tag) {
|
|
2625
|
+
return this.tagMap[tag];
|
|
2626
|
+
}
|
|
2627
|
+
/**
|
|
2628
|
+
* Handle post mapping exceptions / correction
|
|
2629
|
+
* @param tag Tag e.g. {"©alb", "Buena Vista Social Club")
|
|
2630
|
+
* @param warnings Used to register warnings
|
|
2631
|
+
*/
|
|
2632
|
+
postMap(_tag, _warnings) {
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
};
|
|
2636
|
+
CommonTagMapper.maxRatingScore = 1;
|
|
2637
|
+
|
|
2638
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/id3v1/ID3v1TagMap.js
|
|
2639
|
+
var id3v1TagMap = {
|
|
2640
|
+
title: "title",
|
|
2641
|
+
artist: "artist",
|
|
2642
|
+
album: "album",
|
|
2643
|
+
year: "year",
|
|
2644
|
+
comment: "comment",
|
|
2645
|
+
track: "track",
|
|
2646
|
+
genre: "genre"
|
|
2647
|
+
};
|
|
2648
|
+
var ID3v1TagMapper = class extends CommonTagMapper {
|
|
2649
|
+
constructor() {
|
|
2650
|
+
super(["ID3v1"], id3v1TagMap);
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
|
|
2654
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/common/CaseInsensitiveTagMap.js
|
|
2655
|
+
var CaseInsensitiveTagMap = class extends CommonTagMapper {
|
|
2656
|
+
constructor(tagTypes, tagMap2) {
|
|
2657
|
+
const upperCaseMap = {};
|
|
2658
|
+
for (const tag of Object.keys(tagMap2)) {
|
|
2659
|
+
upperCaseMap[tag.toUpperCase()] = tagMap2[tag];
|
|
2660
|
+
}
|
|
2661
|
+
super(tagTypes, upperCaseMap);
|
|
2662
|
+
}
|
|
2663
|
+
/**
|
|
2664
|
+
* @tag Native header tag
|
|
2665
|
+
* @return common tag name (alias)
|
|
2666
|
+
*/
|
|
2667
|
+
getCommonName(tag) {
|
|
2668
|
+
return this.tagMap[tag.toUpperCase()];
|
|
2669
|
+
}
|
|
2670
|
+
};
|
|
2671
|
+
|
|
2672
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/id3v2/ID3v24TagMapper.js
|
|
2673
|
+
var id3v24TagMap = {
|
|
2674
|
+
// id3v2.3
|
|
2675
|
+
TIT2: "title",
|
|
2676
|
+
TPE1: "artist",
|
|
2677
|
+
"TXXX:Artists": "artists",
|
|
2678
|
+
TPE2: "albumartist",
|
|
2679
|
+
TALB: "album",
|
|
2680
|
+
TDRV: "date",
|
|
2681
|
+
// [ 'date', 'year' ] ToDo: improve 'year' mapping
|
|
2682
|
+
/**
|
|
2683
|
+
* Original release year
|
|
2684
|
+
*/
|
|
2685
|
+
TORY: "originalyear",
|
|
2686
|
+
TPOS: "disk",
|
|
2687
|
+
TCON: "genre",
|
|
2688
|
+
APIC: "picture",
|
|
2689
|
+
TCOM: "composer",
|
|
2690
|
+
USLT: "lyrics",
|
|
2691
|
+
TSOA: "albumsort",
|
|
2692
|
+
TSOT: "titlesort",
|
|
2693
|
+
TOAL: "originalalbum",
|
|
2694
|
+
TSOP: "artistsort",
|
|
2695
|
+
TSO2: "albumartistsort",
|
|
2696
|
+
TSOC: "composersort",
|
|
2697
|
+
TEXT: "lyricist",
|
|
2698
|
+
"TXXX:Writer": "writer",
|
|
2699
|
+
TPE3: "conductor",
|
|
2700
|
+
// 'IPLS:instrument': 'performer:instrument', // ToDo
|
|
2701
|
+
TPE4: "remixer",
|
|
2702
|
+
"IPLS:arranger": "arranger",
|
|
2703
|
+
"IPLS:engineer": "engineer",
|
|
2704
|
+
"IPLS:producer": "producer",
|
|
2705
|
+
"IPLS:DJ-mix": "djmixer",
|
|
2706
|
+
"IPLS:mix": "mixer",
|
|
2707
|
+
TPUB: "label",
|
|
2708
|
+
TIT1: "grouping",
|
|
2709
|
+
TIT3: "subtitle",
|
|
2710
|
+
TRCK: "track",
|
|
2711
|
+
TCMP: "compilation",
|
|
2712
|
+
POPM: "rating",
|
|
2713
|
+
TBPM: "bpm",
|
|
2714
|
+
TMED: "media",
|
|
2715
|
+
"TXXX:CATALOGNUMBER": "catalognumber",
|
|
2716
|
+
"TXXX:MusicBrainz Album Status": "releasestatus",
|
|
2717
|
+
"TXXX:MusicBrainz Album Type": "releasetype",
|
|
2718
|
+
/**
|
|
2719
|
+
* Release country as documented: https://picard.musicbrainz.org/docs/mappings/#cite_note-0
|
|
2720
|
+
*/
|
|
2721
|
+
"TXXX:MusicBrainz Album Release Country": "releasecountry",
|
|
2722
|
+
/**
|
|
2723
|
+
* Release country as implemented // ToDo: report
|
|
2724
|
+
*/
|
|
2725
|
+
"TXXX:RELEASECOUNTRY": "releasecountry",
|
|
2726
|
+
"TXXX:SCRIPT": "script",
|
|
2727
|
+
TLAN: "language",
|
|
2728
|
+
TCOP: "copyright",
|
|
2729
|
+
WCOP: "license",
|
|
2730
|
+
TENC: "encodedby",
|
|
2731
|
+
TSSE: "encodersettings",
|
|
2732
|
+
"TXXX:BARCODE": "barcode",
|
|
2733
|
+
"TXXX:ISRC": "isrc",
|
|
2734
|
+
TSRC: "isrc",
|
|
2735
|
+
"TXXX:ASIN": "asin",
|
|
2736
|
+
"TXXX:originalyear": "originalyear",
|
|
2737
|
+
"UFID:http://musicbrainz.org": "musicbrainz_recordingid",
|
|
2738
|
+
"TXXX:MusicBrainz Release Track Id": "musicbrainz_trackid",
|
|
2739
|
+
"TXXX:MusicBrainz Album Id": "musicbrainz_albumid",
|
|
2740
|
+
"TXXX:MusicBrainz Artist Id": "musicbrainz_artistid",
|
|
2741
|
+
"TXXX:MusicBrainz Album Artist Id": "musicbrainz_albumartistid",
|
|
2742
|
+
"TXXX:MusicBrainz Release Group Id": "musicbrainz_releasegroupid",
|
|
2743
|
+
"TXXX:MusicBrainz Work Id": "musicbrainz_workid",
|
|
2744
|
+
"TXXX:MusicBrainz TRM Id": "musicbrainz_trmid",
|
|
2745
|
+
"TXXX:MusicBrainz Disc Id": "musicbrainz_discid",
|
|
2746
|
+
"TXXX:ACOUSTID_ID": "acoustid_id",
|
|
2747
|
+
"TXXX:Acoustid Id": "acoustid_id",
|
|
2748
|
+
"TXXX:Acoustid Fingerprint": "acoustid_fingerprint",
|
|
2749
|
+
"TXXX:MusicIP PUID": "musicip_puid",
|
|
2750
|
+
"TXXX:MusicMagic Fingerprint": "musicip_fingerprint",
|
|
2751
|
+
WOAR: "website",
|
|
2752
|
+
// id3v2.4
|
|
2753
|
+
// ToDo: In same sequence as defined at http://id3.org/id3v2.4.0-frames
|
|
2754
|
+
TDRC: "date",
|
|
2755
|
+
// date YYYY-MM-DD
|
|
2756
|
+
TYER: "year",
|
|
2757
|
+
TDOR: "originaldate",
|
|
2758
|
+
// 'TMCL:instrument': 'performer:instrument',
|
|
2759
|
+
"TIPL:arranger": "arranger",
|
|
2760
|
+
"TIPL:engineer": "engineer",
|
|
2761
|
+
"TIPL:producer": "producer",
|
|
2762
|
+
"TIPL:DJ-mix": "djmixer",
|
|
2763
|
+
"TIPL:mix": "mixer",
|
|
2764
|
+
TMOO: "mood",
|
|
2765
|
+
// additional mappings:
|
|
2766
|
+
SYLT: "lyrics",
|
|
2767
|
+
TSST: "discsubtitle",
|
|
2768
|
+
TKEY: "key",
|
|
2769
|
+
COMM: "comment",
|
|
2770
|
+
TOPE: "originalartist",
|
|
2771
|
+
// Windows Media Player
|
|
2772
|
+
"PRIV:AverageLevel": "averageLevel",
|
|
2773
|
+
"PRIV:PeakLevel": "peakLevel",
|
|
2774
|
+
// Discogs
|
|
2775
|
+
"TXXX:DISCOGS_ARTIST_ID": "discogs_artist_id",
|
|
2776
|
+
"TXXX:DISCOGS_ARTISTS": "artists",
|
|
2777
|
+
"TXXX:DISCOGS_ARTIST_NAME": "artists",
|
|
2778
|
+
"TXXX:DISCOGS_ALBUM_ARTISTS": "albumartist",
|
|
2779
|
+
"TXXX:DISCOGS_CATALOG": "catalognumber",
|
|
2780
|
+
"TXXX:DISCOGS_COUNTRY": "releasecountry",
|
|
2781
|
+
"TXXX:DISCOGS_DATE": "originaldate",
|
|
2782
|
+
"TXXX:DISCOGS_LABEL": "label",
|
|
2783
|
+
"TXXX:DISCOGS_LABEL_ID": "discogs_label_id",
|
|
2784
|
+
"TXXX:DISCOGS_MASTER_RELEASE_ID": "discogs_master_release_id",
|
|
2785
|
+
"TXXX:DISCOGS_RATING": "discogs_rating",
|
|
2786
|
+
"TXXX:DISCOGS_RELEASED": "date",
|
|
2787
|
+
"TXXX:DISCOGS_RELEASE_ID": "discogs_release_id",
|
|
2788
|
+
"TXXX:DISCOGS_VOTES": "discogs_votes",
|
|
2789
|
+
"TXXX:CATALOGID": "catalognumber",
|
|
2790
|
+
"TXXX:STYLE": "genre",
|
|
2791
|
+
"TXXX:REPLAYGAIN_TRACK_PEAK": "replaygain_track_peak",
|
|
2792
|
+
"TXXX:REPLAYGAIN_TRACK_GAIN": "replaygain_track_gain",
|
|
2793
|
+
"TXXX:REPLAYGAIN_ALBUM_PEAK": "replaygain_album_peak",
|
|
2794
|
+
"TXXX:REPLAYGAIN_ALBUM_GAIN": "replaygain_album_gain",
|
|
2795
|
+
"TXXX:MP3GAIN_MINMAX": "replaygain_track_minmax",
|
|
2796
|
+
"TXXX:MP3GAIN_ALBUM_MINMAX": "replaygain_album_minmax",
|
|
2797
|
+
"TXXX:MP3GAIN_UNDO": "replaygain_undo",
|
|
2798
|
+
MVNM: "movement",
|
|
2799
|
+
MVIN: "movementIndex",
|
|
2800
|
+
PCST: "podcast",
|
|
2801
|
+
TCAT: "category",
|
|
2802
|
+
TDES: "description",
|
|
2803
|
+
TDRL: "releasedate",
|
|
2804
|
+
TGID: "podcastId",
|
|
2805
|
+
TKWD: "keywords",
|
|
2806
|
+
WFED: "podcasturl",
|
|
2807
|
+
GRP1: "grouping",
|
|
2808
|
+
PCNT: "playCounter"
|
|
2809
|
+
};
|
|
2810
|
+
var ID3v24TagMapper = class _ID3v24TagMapper extends CaseInsensitiveTagMap {
|
|
2811
|
+
static toRating(popm) {
|
|
2812
|
+
return {
|
|
2813
|
+
source: popm.email,
|
|
2814
|
+
rating: popm.rating > 0 ? (popm.rating - 1) / 254 * CommonTagMapper.maxRatingScore : void 0
|
|
2815
|
+
};
|
|
2816
|
+
}
|
|
2817
|
+
constructor() {
|
|
2818
|
+
super(["ID3v2.3", "ID3v2.4"], id3v24TagMap);
|
|
2819
|
+
}
|
|
2820
|
+
/**
|
|
2821
|
+
* Handle post mapping exceptions / correction
|
|
2822
|
+
* @param tag to post map
|
|
2823
|
+
* @param warnings Wil be used to register (collect) warnings
|
|
2824
|
+
*/
|
|
2825
|
+
postMap(tag, warnings) {
|
|
2826
|
+
switch (tag.id) {
|
|
2827
|
+
case "UFID":
|
|
2828
|
+
{
|
|
2829
|
+
const idTag = tag.value;
|
|
2830
|
+
if (idTag.owner_identifier === "http://musicbrainz.org") {
|
|
2831
|
+
tag.id += `:${idTag.owner_identifier}`;
|
|
2832
|
+
tag.value = decodeString(idTag.identifier, "latin1");
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
break;
|
|
2836
|
+
case "PRIV":
|
|
2837
|
+
{
|
|
2838
|
+
const customTag = tag.value;
|
|
2839
|
+
switch (customTag.owner_identifier) {
|
|
2840
|
+
// decode Windows Media Player
|
|
2841
|
+
case "AverageLevel":
|
|
2842
|
+
case "PeakValue":
|
|
2843
|
+
tag.id += `:${customTag.owner_identifier}`;
|
|
2844
|
+
tag.value = customTag.data.length === 4 ? UINT32_LE.get(customTag.data, 0) : null;
|
|
2845
|
+
if (tag.value === null) {
|
|
2846
|
+
warnings.addWarning("Failed to parse PRIV:PeakValue");
|
|
2847
|
+
}
|
|
2848
|
+
break;
|
|
2849
|
+
default:
|
|
2850
|
+
warnings.addWarning(`Unknown PRIV owner-identifier: ${customTag.data}`);
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
break;
|
|
2854
|
+
case "POPM":
|
|
2855
|
+
tag.value = _ID3v24TagMapper.toRating(tag.value);
|
|
2856
|
+
break;
|
|
2857
|
+
default:
|
|
2858
|
+
break;
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
};
|
|
2862
|
+
|
|
2863
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/asf/AsfTagMapper.js
|
|
2864
|
+
var asfTagMap = {
|
|
2865
|
+
Title: "title",
|
|
2866
|
+
Author: "artist",
|
|
2867
|
+
"WM/AlbumArtist": "albumartist",
|
|
2868
|
+
"WM/AlbumTitle": "album",
|
|
2869
|
+
"WM/Year": "date",
|
|
2870
|
+
// changed to 'year' to 'date' based on Picard mappings; ToDo: check me
|
|
2871
|
+
"WM/OriginalReleaseTime": "originaldate",
|
|
2872
|
+
"WM/OriginalReleaseYear": "originalyear",
|
|
2873
|
+
Description: "comment",
|
|
2874
|
+
"WM/TrackNumber": "track",
|
|
2875
|
+
"WM/PartOfSet": "disk",
|
|
2876
|
+
"WM/Genre": "genre",
|
|
2877
|
+
"WM/Composer": "composer",
|
|
2878
|
+
"WM/Lyrics": "lyrics",
|
|
2879
|
+
"WM/AlbumSortOrder": "albumsort",
|
|
2880
|
+
"WM/TitleSortOrder": "titlesort",
|
|
2881
|
+
"WM/ArtistSortOrder": "artistsort",
|
|
2882
|
+
"WM/AlbumArtistSortOrder": "albumartistsort",
|
|
2883
|
+
"WM/ComposerSortOrder": "composersort",
|
|
2884
|
+
"WM/Writer": "lyricist",
|
|
2885
|
+
"WM/Conductor": "conductor",
|
|
2886
|
+
"WM/ModifiedBy": "remixer",
|
|
2887
|
+
"WM/Engineer": "engineer",
|
|
2888
|
+
"WM/Producer": "producer",
|
|
2889
|
+
"WM/DJMixer": "djmixer",
|
|
2890
|
+
"WM/Mixer": "mixer",
|
|
2891
|
+
"WM/Publisher": "label",
|
|
2892
|
+
"WM/ContentGroupDescription": "grouping",
|
|
2893
|
+
"WM/SubTitle": "subtitle",
|
|
2894
|
+
"WM/SetSubTitle": "discsubtitle",
|
|
2895
|
+
// 'WM/PartOfSet': 'totaldiscs',
|
|
2896
|
+
"WM/IsCompilation": "compilation",
|
|
2897
|
+
"WM/SharedUserRating": "rating",
|
|
2898
|
+
"WM/BeatsPerMinute": "bpm",
|
|
2899
|
+
"WM/Mood": "mood",
|
|
2900
|
+
"WM/Media": "media",
|
|
2901
|
+
"WM/CatalogNo": "catalognumber",
|
|
2902
|
+
"MusicBrainz/Album Status": "releasestatus",
|
|
2903
|
+
"MusicBrainz/Album Type": "releasetype",
|
|
2904
|
+
"MusicBrainz/Album Release Country": "releasecountry",
|
|
2905
|
+
"WM/Script": "script",
|
|
2906
|
+
"WM/Language": "language",
|
|
2907
|
+
Copyright: "copyright",
|
|
2908
|
+
LICENSE: "license",
|
|
2909
|
+
"WM/EncodedBy": "encodedby",
|
|
2910
|
+
"WM/EncodingSettings": "encodersettings",
|
|
2911
|
+
"WM/Barcode": "barcode",
|
|
2912
|
+
"WM/ISRC": "isrc",
|
|
2913
|
+
"MusicBrainz/Track Id": "musicbrainz_recordingid",
|
|
2914
|
+
"MusicBrainz/Release Track Id": "musicbrainz_trackid",
|
|
2915
|
+
"MusicBrainz/Album Id": "musicbrainz_albumid",
|
|
2916
|
+
"MusicBrainz/Artist Id": "musicbrainz_artistid",
|
|
2917
|
+
"MusicBrainz/Album Artist Id": "musicbrainz_albumartistid",
|
|
2918
|
+
"MusicBrainz/Release Group Id": "musicbrainz_releasegroupid",
|
|
2919
|
+
"MusicBrainz/Work Id": "musicbrainz_workid",
|
|
2920
|
+
"MusicBrainz/TRM Id": "musicbrainz_trmid",
|
|
2921
|
+
"MusicBrainz/Disc Id": "musicbrainz_discid",
|
|
2922
|
+
"Acoustid/Id": "acoustid_id",
|
|
2923
|
+
"Acoustid/Fingerprint": "acoustid_fingerprint",
|
|
2924
|
+
"MusicIP/PUID": "musicip_puid",
|
|
2925
|
+
"WM/ARTISTS": "artists",
|
|
2926
|
+
"WM/InitialKey": "key",
|
|
2927
|
+
ASIN: "asin",
|
|
2928
|
+
"WM/Work": "work",
|
|
2929
|
+
"WM/AuthorURL": "website",
|
|
2930
|
+
"WM/Picture": "picture"
|
|
2931
|
+
};
|
|
2932
|
+
var AsfTagMapper = class _AsfTagMapper extends CommonTagMapper {
|
|
2933
|
+
static toRating(rating) {
|
|
2934
|
+
return {
|
|
2935
|
+
rating: Number.parseFloat(rating + 1) / 5
|
|
2936
|
+
};
|
|
2937
|
+
}
|
|
2938
|
+
constructor() {
|
|
2939
|
+
super(["asf"], asfTagMap);
|
|
2940
|
+
}
|
|
2941
|
+
postMap(tag) {
|
|
2942
|
+
switch (tag.id) {
|
|
2943
|
+
case "WM/SharedUserRating": {
|
|
2944
|
+
const keys = tag.id.split(":");
|
|
2945
|
+
tag.value = _AsfTagMapper.toRating(tag.value);
|
|
2946
|
+
tag.id = keys[0];
|
|
2947
|
+
break;
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
};
|
|
2952
|
+
|
|
2953
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/id3v2/ID3v22TagMapper.js
|
|
2954
|
+
var id3v22TagMap = {
|
|
2955
|
+
TT2: "title",
|
|
2956
|
+
TP1: "artist",
|
|
2957
|
+
TP2: "albumartist",
|
|
2958
|
+
TAL: "album",
|
|
2959
|
+
TYE: "year",
|
|
2960
|
+
COM: "comment",
|
|
2961
|
+
TRK: "track",
|
|
2962
|
+
TPA: "disk",
|
|
2963
|
+
TCO: "genre",
|
|
2964
|
+
PIC: "picture",
|
|
2965
|
+
TCM: "composer",
|
|
2966
|
+
TOR: "originaldate",
|
|
2967
|
+
TOT: "originalalbum",
|
|
2968
|
+
TXT: "lyricist",
|
|
2969
|
+
TP3: "conductor",
|
|
2970
|
+
TPB: "label",
|
|
2971
|
+
TT1: "grouping",
|
|
2972
|
+
TT3: "subtitle",
|
|
2973
|
+
TLA: "language",
|
|
2974
|
+
TCR: "copyright",
|
|
2975
|
+
WCP: "license",
|
|
2976
|
+
TEN: "encodedby",
|
|
2977
|
+
TSS: "encodersettings",
|
|
2978
|
+
WAR: "website",
|
|
2979
|
+
PCS: "podcast",
|
|
2980
|
+
TCP: "compilation",
|
|
2981
|
+
TDR: "date",
|
|
2982
|
+
TS2: "albumartistsort",
|
|
2983
|
+
TSA: "albumsort",
|
|
2984
|
+
TSC: "composersort",
|
|
2985
|
+
TSP: "artistsort",
|
|
2986
|
+
TST: "titlesort",
|
|
2987
|
+
WFD: "podcasturl",
|
|
2988
|
+
TBP: "bpm",
|
|
2989
|
+
GP1: "grouping"
|
|
2990
|
+
};
|
|
2991
|
+
var ID3v22TagMapper = class extends CaseInsensitiveTagMap {
|
|
2992
|
+
constructor() {
|
|
2993
|
+
super(["ID3v2.2"], id3v22TagMap);
|
|
2994
|
+
}
|
|
2995
|
+
};
|
|
2996
|
+
|
|
2997
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/apev2/APEv2TagMapper.js
|
|
2998
|
+
var apev2TagMap = {
|
|
2999
|
+
Title: "title",
|
|
3000
|
+
Artist: "artist",
|
|
3001
|
+
Artists: "artists",
|
|
3002
|
+
"Album Artist": "albumartist",
|
|
3003
|
+
Album: "album",
|
|
3004
|
+
Year: "date",
|
|
3005
|
+
Originalyear: "originalyear",
|
|
3006
|
+
Originaldate: "originaldate",
|
|
3007
|
+
Releasedate: "releasedate",
|
|
3008
|
+
Comment: "comment",
|
|
3009
|
+
Track: "track",
|
|
3010
|
+
Disc: "disk",
|
|
3011
|
+
DISCNUMBER: "disk",
|
|
3012
|
+
// ToDo: backwards compatibility', valid tag?
|
|
3013
|
+
Genre: "genre",
|
|
3014
|
+
"Cover Art (Front)": "picture",
|
|
3015
|
+
"Cover Art (Back)": "picture",
|
|
3016
|
+
Composer: "composer",
|
|
3017
|
+
Lyrics: "lyrics",
|
|
3018
|
+
ALBUMSORT: "albumsort",
|
|
3019
|
+
TITLESORT: "titlesort",
|
|
3020
|
+
WORK: "work",
|
|
3021
|
+
ARTISTSORT: "artistsort",
|
|
3022
|
+
ALBUMARTISTSORT: "albumartistsort",
|
|
3023
|
+
COMPOSERSORT: "composersort",
|
|
3024
|
+
Lyricist: "lyricist",
|
|
3025
|
+
Writer: "writer",
|
|
3026
|
+
Conductor: "conductor",
|
|
3027
|
+
// 'Performer=artist (instrument)': 'performer:instrument',
|
|
3028
|
+
MixArtist: "remixer",
|
|
3029
|
+
Arranger: "arranger",
|
|
3030
|
+
Engineer: "engineer",
|
|
3031
|
+
Producer: "producer",
|
|
3032
|
+
DJMixer: "djmixer",
|
|
3033
|
+
Mixer: "mixer",
|
|
3034
|
+
Label: "label",
|
|
3035
|
+
Grouping: "grouping",
|
|
3036
|
+
Subtitle: "subtitle",
|
|
3037
|
+
DiscSubtitle: "discsubtitle",
|
|
3038
|
+
Compilation: "compilation",
|
|
3039
|
+
BPM: "bpm",
|
|
3040
|
+
Mood: "mood",
|
|
3041
|
+
Media: "media",
|
|
3042
|
+
CatalogNumber: "catalognumber",
|
|
3043
|
+
MUSICBRAINZ_ALBUMSTATUS: "releasestatus",
|
|
3044
|
+
MUSICBRAINZ_ALBUMTYPE: "releasetype",
|
|
3045
|
+
RELEASECOUNTRY: "releasecountry",
|
|
3046
|
+
Script: "script",
|
|
3047
|
+
Language: "language",
|
|
3048
|
+
Copyright: "copyright",
|
|
3049
|
+
LICENSE: "license",
|
|
3050
|
+
EncodedBy: "encodedby",
|
|
3051
|
+
EncoderSettings: "encodersettings",
|
|
3052
|
+
Barcode: "barcode",
|
|
3053
|
+
ISRC: "isrc",
|
|
3054
|
+
ASIN: "asin",
|
|
3055
|
+
musicbrainz_trackid: "musicbrainz_recordingid",
|
|
3056
|
+
musicbrainz_releasetrackid: "musicbrainz_trackid",
|
|
3057
|
+
MUSICBRAINZ_ALBUMID: "musicbrainz_albumid",
|
|
3058
|
+
MUSICBRAINZ_ARTISTID: "musicbrainz_artistid",
|
|
3059
|
+
MUSICBRAINZ_ALBUMARTISTID: "musicbrainz_albumartistid",
|
|
3060
|
+
MUSICBRAINZ_RELEASEGROUPID: "musicbrainz_releasegroupid",
|
|
3061
|
+
MUSICBRAINZ_WORKID: "musicbrainz_workid",
|
|
3062
|
+
MUSICBRAINZ_TRMID: "musicbrainz_trmid",
|
|
3063
|
+
MUSICBRAINZ_DISCID: "musicbrainz_discid",
|
|
3064
|
+
Acoustid_Id: "acoustid_id",
|
|
3065
|
+
ACOUSTID_FINGERPRINT: "acoustid_fingerprint",
|
|
3066
|
+
MUSICIP_PUID: "musicip_puid",
|
|
3067
|
+
Weblink: "website",
|
|
3068
|
+
REPLAYGAIN_TRACK_GAIN: "replaygain_track_gain",
|
|
3069
|
+
REPLAYGAIN_TRACK_PEAK: "replaygain_track_peak",
|
|
3070
|
+
MP3GAIN_MINMAX: "replaygain_track_minmax",
|
|
3071
|
+
MP3GAIN_UNDO: "replaygain_undo"
|
|
3072
|
+
};
|
|
3073
|
+
var APEv2TagMapper = class extends CaseInsensitiveTagMap {
|
|
3074
|
+
constructor() {
|
|
3075
|
+
super(["APEv2"], apev2TagMap);
|
|
3076
|
+
}
|
|
3077
|
+
};
|
|
3078
|
+
|
|
3079
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/mp4/MP4TagMapper.js
|
|
3080
|
+
var mp4TagMap = {
|
|
3081
|
+
"\xA9nam": "title",
|
|
3082
|
+
"\xA9ART": "artist",
|
|
3083
|
+
aART: "albumartist",
|
|
3084
|
+
/**
|
|
3085
|
+
* ToDo: Album artist seems to be stored here while Picard documentation says: aART
|
|
3086
|
+
*/
|
|
3087
|
+
"----:com.apple.iTunes:Band": "albumartist",
|
|
3088
|
+
"\xA9alb": "album",
|
|
3089
|
+
"\xA9day": "date",
|
|
3090
|
+
"\xA9cmt": "comment",
|
|
3091
|
+
"\xA9com": "comment",
|
|
3092
|
+
trkn: "track",
|
|
3093
|
+
disk: "disk",
|
|
3094
|
+
"\xA9gen": "genre",
|
|
3095
|
+
covr: "picture",
|
|
3096
|
+
"\xA9wrt": "composer",
|
|
3097
|
+
"\xA9lyr": "lyrics",
|
|
3098
|
+
soal: "albumsort",
|
|
3099
|
+
sonm: "titlesort",
|
|
3100
|
+
soar: "artistsort",
|
|
3101
|
+
soaa: "albumartistsort",
|
|
3102
|
+
soco: "composersort",
|
|
3103
|
+
"----:com.apple.iTunes:LYRICIST": "lyricist",
|
|
3104
|
+
"----:com.apple.iTunes:CONDUCTOR": "conductor",
|
|
3105
|
+
"----:com.apple.iTunes:REMIXER": "remixer",
|
|
3106
|
+
"----:com.apple.iTunes:ENGINEER": "engineer",
|
|
3107
|
+
"----:com.apple.iTunes:PRODUCER": "producer",
|
|
3108
|
+
"----:com.apple.iTunes:DJMIXER": "djmixer",
|
|
3109
|
+
"----:com.apple.iTunes:MIXER": "mixer",
|
|
3110
|
+
"----:com.apple.iTunes:LABEL": "label",
|
|
3111
|
+
"\xA9grp": "grouping",
|
|
3112
|
+
"----:com.apple.iTunes:SUBTITLE": "subtitle",
|
|
3113
|
+
"----:com.apple.iTunes:DISCSUBTITLE": "discsubtitle",
|
|
3114
|
+
cpil: "compilation",
|
|
3115
|
+
tmpo: "bpm",
|
|
3116
|
+
"----:com.apple.iTunes:MOOD": "mood",
|
|
3117
|
+
"----:com.apple.iTunes:MEDIA": "media",
|
|
3118
|
+
"----:com.apple.iTunes:CATALOGNUMBER": "catalognumber",
|
|
3119
|
+
tvsh: "tvShow",
|
|
3120
|
+
tvsn: "tvSeason",
|
|
3121
|
+
tves: "tvEpisode",
|
|
3122
|
+
sosn: "tvShowSort",
|
|
3123
|
+
tven: "tvEpisodeId",
|
|
3124
|
+
tvnn: "tvNetwork",
|
|
3125
|
+
pcst: "podcast",
|
|
3126
|
+
purl: "podcasturl",
|
|
3127
|
+
"----:com.apple.iTunes:MusicBrainz Album Status": "releasestatus",
|
|
3128
|
+
"----:com.apple.iTunes:MusicBrainz Album Type": "releasetype",
|
|
3129
|
+
"----:com.apple.iTunes:MusicBrainz Album Release Country": "releasecountry",
|
|
3130
|
+
"----:com.apple.iTunes:SCRIPT": "script",
|
|
3131
|
+
"----:com.apple.iTunes:LANGUAGE": "language",
|
|
3132
|
+
cprt: "copyright",
|
|
3133
|
+
"\xA9cpy": "copyright",
|
|
3134
|
+
"----:com.apple.iTunes:LICENSE": "license",
|
|
3135
|
+
"\xA9too": "encodedby",
|
|
3136
|
+
pgap: "gapless",
|
|
3137
|
+
"----:com.apple.iTunes:BARCODE": "barcode",
|
|
3138
|
+
"----:com.apple.iTunes:ISRC": "isrc",
|
|
3139
|
+
"----:com.apple.iTunes:ASIN": "asin",
|
|
3140
|
+
"----:com.apple.iTunes:NOTES": "comment",
|
|
3141
|
+
"----:com.apple.iTunes:MusicBrainz Track Id": "musicbrainz_recordingid",
|
|
3142
|
+
"----:com.apple.iTunes:MusicBrainz Release Track Id": "musicbrainz_trackid",
|
|
3143
|
+
"----:com.apple.iTunes:MusicBrainz Album Id": "musicbrainz_albumid",
|
|
3144
|
+
"----:com.apple.iTunes:MusicBrainz Artist Id": "musicbrainz_artistid",
|
|
3145
|
+
"----:com.apple.iTunes:MusicBrainz Album Artist Id": "musicbrainz_albumartistid",
|
|
3146
|
+
"----:com.apple.iTunes:MusicBrainz Release Group Id": "musicbrainz_releasegroupid",
|
|
3147
|
+
"----:com.apple.iTunes:MusicBrainz Work Id": "musicbrainz_workid",
|
|
3148
|
+
"----:com.apple.iTunes:MusicBrainz TRM Id": "musicbrainz_trmid",
|
|
3149
|
+
"----:com.apple.iTunes:MusicBrainz Disc Id": "musicbrainz_discid",
|
|
3150
|
+
"----:com.apple.iTunes:Acoustid Id": "acoustid_id",
|
|
3151
|
+
"----:com.apple.iTunes:Acoustid Fingerprint": "acoustid_fingerprint",
|
|
3152
|
+
"----:com.apple.iTunes:MusicIP PUID": "musicip_puid",
|
|
3153
|
+
"----:com.apple.iTunes:fingerprint": "musicip_fingerprint",
|
|
3154
|
+
"----:com.apple.iTunes:replaygain_track_gain": "replaygain_track_gain",
|
|
3155
|
+
"----:com.apple.iTunes:replaygain_track_peak": "replaygain_track_peak",
|
|
3156
|
+
"----:com.apple.iTunes:replaygain_album_gain": "replaygain_album_gain",
|
|
3157
|
+
"----:com.apple.iTunes:replaygain_album_peak": "replaygain_album_peak",
|
|
3158
|
+
"----:com.apple.iTunes:replaygain_track_minmax": "replaygain_track_minmax",
|
|
3159
|
+
"----:com.apple.iTunes:replaygain_album_minmax": "replaygain_album_minmax",
|
|
3160
|
+
"----:com.apple.iTunes:replaygain_undo": "replaygain_undo",
|
|
3161
|
+
// Additional mappings:
|
|
3162
|
+
gnre: "genre",
|
|
3163
|
+
// ToDo: check mapping
|
|
3164
|
+
"----:com.apple.iTunes:ALBUMARTISTSORT": "albumartistsort",
|
|
3165
|
+
"----:com.apple.iTunes:ARTISTS": "artists",
|
|
3166
|
+
"----:com.apple.iTunes:ORIGINALDATE": "originaldate",
|
|
3167
|
+
"----:com.apple.iTunes:ORIGINALYEAR": "originalyear",
|
|
3168
|
+
"----:com.apple.iTunes:RELEASEDATE": "releasedate",
|
|
3169
|
+
// '----:com.apple.iTunes:PERFORMER': 'performer'
|
|
3170
|
+
desc: "description",
|
|
3171
|
+
ldes: "longDescription",
|
|
3172
|
+
"\xA9mvn": "movement",
|
|
3173
|
+
"\xA9mvi": "movementIndex",
|
|
3174
|
+
"\xA9mvc": "movementTotal",
|
|
3175
|
+
"\xA9wrk": "work",
|
|
3176
|
+
catg: "category",
|
|
3177
|
+
egid: "podcastId",
|
|
3178
|
+
hdvd: "hdVideo",
|
|
3179
|
+
keyw: "keywords",
|
|
3180
|
+
shwm: "showMovement",
|
|
3181
|
+
stik: "stik",
|
|
3182
|
+
rate: "rating"
|
|
3183
|
+
};
|
|
3184
|
+
var tagType = "iTunes";
|
|
3185
|
+
var MP4TagMapper = class extends CaseInsensitiveTagMap {
|
|
3186
|
+
constructor() {
|
|
3187
|
+
super([tagType], mp4TagMap);
|
|
3188
|
+
}
|
|
3189
|
+
postMap(tag, _warnings) {
|
|
3190
|
+
switch (tag.id) {
|
|
3191
|
+
case "rate":
|
|
3192
|
+
tag.value = {
|
|
3193
|
+
source: void 0,
|
|
3194
|
+
rating: Number.parseFloat(tag.value) / 100
|
|
3195
|
+
};
|
|
3196
|
+
break;
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
};
|
|
3200
|
+
|
|
3201
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/ogg/vorbis/VorbisTagMapper.js
|
|
3202
|
+
var vorbisTagMap = {
|
|
3203
|
+
TITLE: "title",
|
|
3204
|
+
ARTIST: "artist",
|
|
3205
|
+
ARTISTS: "artists",
|
|
3206
|
+
ALBUMARTIST: "albumartist",
|
|
3207
|
+
"ALBUM ARTIST": "albumartist",
|
|
3208
|
+
ALBUM: "album",
|
|
3209
|
+
DATE: "date",
|
|
3210
|
+
ORIGINALDATE: "originaldate",
|
|
3211
|
+
ORIGINALYEAR: "originalyear",
|
|
3212
|
+
RELEASEDATE: "releasedate",
|
|
3213
|
+
COMMENT: "comment",
|
|
3214
|
+
TRACKNUMBER: "track",
|
|
3215
|
+
DISCNUMBER: "disk",
|
|
3216
|
+
GENRE: "genre",
|
|
3217
|
+
METADATA_BLOCK_PICTURE: "picture",
|
|
3218
|
+
COMPOSER: "composer",
|
|
3219
|
+
LYRICS: "lyrics",
|
|
3220
|
+
ALBUMSORT: "albumsort",
|
|
3221
|
+
TITLESORT: "titlesort",
|
|
3222
|
+
WORK: "work",
|
|
3223
|
+
ARTISTSORT: "artistsort",
|
|
3224
|
+
ALBUMARTISTSORT: "albumartistsort",
|
|
3225
|
+
COMPOSERSORT: "composersort",
|
|
3226
|
+
LYRICIST: "lyricist",
|
|
3227
|
+
WRITER: "writer",
|
|
3228
|
+
CONDUCTOR: "conductor",
|
|
3229
|
+
// 'PERFORMER=artist (instrument)': 'performer:instrument', // ToDo
|
|
3230
|
+
REMIXER: "remixer",
|
|
3231
|
+
ARRANGER: "arranger",
|
|
3232
|
+
ENGINEER: "engineer",
|
|
3233
|
+
PRODUCER: "producer",
|
|
3234
|
+
DJMIXER: "djmixer",
|
|
3235
|
+
MIXER: "mixer",
|
|
3236
|
+
LABEL: "label",
|
|
3237
|
+
GROUPING: "grouping",
|
|
3238
|
+
SUBTITLE: "subtitle",
|
|
3239
|
+
DISCSUBTITLE: "discsubtitle",
|
|
3240
|
+
TRACKTOTAL: "totaltracks",
|
|
3241
|
+
DISCTOTAL: "totaldiscs",
|
|
3242
|
+
COMPILATION: "compilation",
|
|
3243
|
+
RATING: "rating",
|
|
3244
|
+
BPM: "bpm",
|
|
3245
|
+
KEY: "key",
|
|
3246
|
+
MOOD: "mood",
|
|
3247
|
+
MEDIA: "media",
|
|
3248
|
+
CATALOGNUMBER: "catalognumber",
|
|
3249
|
+
RELEASESTATUS: "releasestatus",
|
|
3250
|
+
RELEASETYPE: "releasetype",
|
|
3251
|
+
RELEASECOUNTRY: "releasecountry",
|
|
3252
|
+
SCRIPT: "script",
|
|
3253
|
+
LANGUAGE: "language",
|
|
3254
|
+
COPYRIGHT: "copyright",
|
|
3255
|
+
LICENSE: "license",
|
|
3256
|
+
ENCODEDBY: "encodedby",
|
|
3257
|
+
ENCODERSETTINGS: "encodersettings",
|
|
3258
|
+
BARCODE: "barcode",
|
|
3259
|
+
ISRC: "isrc",
|
|
3260
|
+
ASIN: "asin",
|
|
3261
|
+
MUSICBRAINZ_TRACKID: "musicbrainz_recordingid",
|
|
3262
|
+
MUSICBRAINZ_RELEASETRACKID: "musicbrainz_trackid",
|
|
3263
|
+
MUSICBRAINZ_ALBUMID: "musicbrainz_albumid",
|
|
3264
|
+
MUSICBRAINZ_ARTISTID: "musicbrainz_artistid",
|
|
3265
|
+
MUSICBRAINZ_ALBUMARTISTID: "musicbrainz_albumartistid",
|
|
3266
|
+
MUSICBRAINZ_RELEASEGROUPID: "musicbrainz_releasegroupid",
|
|
3267
|
+
MUSICBRAINZ_WORKID: "musicbrainz_workid",
|
|
3268
|
+
MUSICBRAINZ_TRMID: "musicbrainz_trmid",
|
|
3269
|
+
MUSICBRAINZ_DISCID: "musicbrainz_discid",
|
|
3270
|
+
ACOUSTID_ID: "acoustid_id",
|
|
3271
|
+
ACOUSTID_ID_FINGERPRINT: "acoustid_fingerprint",
|
|
3272
|
+
MUSICIP_PUID: "musicip_puid",
|
|
3273
|
+
// 'FINGERPRINT=MusicMagic Fingerprint {fingerprint}': 'musicip_fingerprint', // ToDo
|
|
3274
|
+
WEBSITE: "website",
|
|
3275
|
+
NOTES: "notes",
|
|
3276
|
+
TOTALTRACKS: "totaltracks",
|
|
3277
|
+
TOTALDISCS: "totaldiscs",
|
|
3278
|
+
// Discogs
|
|
3279
|
+
DISCOGS_ARTIST_ID: "discogs_artist_id",
|
|
3280
|
+
DISCOGS_ARTISTS: "artists",
|
|
3281
|
+
DISCOGS_ARTIST_NAME: "artists",
|
|
3282
|
+
DISCOGS_ALBUM_ARTISTS: "albumartist",
|
|
3283
|
+
DISCOGS_CATALOG: "catalognumber",
|
|
3284
|
+
DISCOGS_COUNTRY: "releasecountry",
|
|
3285
|
+
DISCOGS_DATE: "originaldate",
|
|
3286
|
+
DISCOGS_LABEL: "label",
|
|
3287
|
+
DISCOGS_LABEL_ID: "discogs_label_id",
|
|
3288
|
+
DISCOGS_MASTER_RELEASE_ID: "discogs_master_release_id",
|
|
3289
|
+
DISCOGS_RATING: "discogs_rating",
|
|
3290
|
+
DISCOGS_RELEASED: "date",
|
|
3291
|
+
DISCOGS_RELEASE_ID: "discogs_release_id",
|
|
3292
|
+
DISCOGS_VOTES: "discogs_votes",
|
|
3293
|
+
CATALOGID: "catalognumber",
|
|
3294
|
+
STYLE: "genre",
|
|
3295
|
+
//
|
|
3296
|
+
REPLAYGAIN_TRACK_GAIN: "replaygain_track_gain",
|
|
3297
|
+
REPLAYGAIN_TRACK_PEAK: "replaygain_track_peak",
|
|
3298
|
+
REPLAYGAIN_ALBUM_GAIN: "replaygain_album_gain",
|
|
3299
|
+
REPLAYGAIN_ALBUM_PEAK: "replaygain_album_peak",
|
|
3300
|
+
// To Sure if these (REPLAYGAIN_MINMAX, REPLAYGAIN_ALBUM_MINMAX & REPLAYGAIN_UNDO) are used for Vorbis:
|
|
3301
|
+
REPLAYGAIN_MINMAX: "replaygain_track_minmax",
|
|
3302
|
+
REPLAYGAIN_ALBUM_MINMAX: "replaygain_album_minmax",
|
|
3303
|
+
REPLAYGAIN_UNDO: "replaygain_undo"
|
|
3304
|
+
};
|
|
3305
|
+
var VorbisTagMapper = class _VorbisTagMapper extends CommonTagMapper {
|
|
3306
|
+
static toRating(email, rating, maxScore) {
|
|
3307
|
+
return {
|
|
3308
|
+
source: email ? email.toLowerCase() : void 0,
|
|
3309
|
+
rating: Number.parseFloat(rating) / maxScore * CommonTagMapper.maxRatingScore
|
|
3310
|
+
};
|
|
3311
|
+
}
|
|
3312
|
+
constructor() {
|
|
3313
|
+
super(["vorbis"], vorbisTagMap);
|
|
3314
|
+
}
|
|
3315
|
+
postMap(tag) {
|
|
3316
|
+
if (tag.id === "RATING") {
|
|
3317
|
+
tag.value = _VorbisTagMapper.toRating(void 0, tag.value, 100);
|
|
3318
|
+
} else if (tag.id.indexOf("RATING:") === 0) {
|
|
3319
|
+
const keys = tag.id.split(":");
|
|
3320
|
+
tag.value = _VorbisTagMapper.toRating(keys[1], tag.value, 1);
|
|
3321
|
+
tag.id = keys[0];
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
};
|
|
3325
|
+
|
|
3326
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/riff/RiffInfoTagMap.js
|
|
3327
|
+
var riffInfoTagMap = {
|
|
3328
|
+
IART: "artist",
|
|
3329
|
+
// Artist
|
|
3330
|
+
ICRD: "date",
|
|
3331
|
+
// DateCreated
|
|
3332
|
+
INAM: "title",
|
|
3333
|
+
// Title
|
|
3334
|
+
TITL: "title",
|
|
3335
|
+
IPRD: "album",
|
|
3336
|
+
// Product
|
|
3337
|
+
ITRK: "track",
|
|
3338
|
+
IPRT: "track",
|
|
3339
|
+
// Additional tag for track index
|
|
3340
|
+
COMM: "comment",
|
|
3341
|
+
// Comments
|
|
3342
|
+
ICMT: "comment",
|
|
3343
|
+
// Country
|
|
3344
|
+
ICNT: "releasecountry",
|
|
3345
|
+
GNRE: "genre",
|
|
3346
|
+
// Genre
|
|
3347
|
+
IWRI: "writer",
|
|
3348
|
+
// WrittenBy
|
|
3349
|
+
RATE: "rating",
|
|
3350
|
+
YEAR: "year",
|
|
3351
|
+
ISFT: "encodedby",
|
|
3352
|
+
// Software
|
|
3353
|
+
CODE: "encodedby",
|
|
3354
|
+
// EncodedBy
|
|
3355
|
+
TURL: "website",
|
|
3356
|
+
// URL,
|
|
3357
|
+
IGNR: "genre",
|
|
3358
|
+
// Genre
|
|
3359
|
+
IENG: "engineer",
|
|
3360
|
+
// Engineer
|
|
3361
|
+
ITCH: "technician",
|
|
3362
|
+
// Technician
|
|
3363
|
+
IMED: "media",
|
|
3364
|
+
// Original Media
|
|
3365
|
+
IRPD: "album"
|
|
3366
|
+
// Product, where the file was intended for
|
|
3367
|
+
};
|
|
3368
|
+
var RiffInfoTagMapper = class extends CommonTagMapper {
|
|
3369
|
+
constructor() {
|
|
3370
|
+
super(["exif"], riffInfoTagMap);
|
|
3371
|
+
}
|
|
3372
|
+
};
|
|
3373
|
+
|
|
3374
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/matroska/MatroskaTagMapper.js
|
|
3375
|
+
var ebmlTagMap = {
|
|
3376
|
+
"segment:title": "title",
|
|
3377
|
+
"album:ARTIST": "albumartist",
|
|
3378
|
+
"album:ARTISTSORT": "albumartistsort",
|
|
3379
|
+
"album:TITLE": "album",
|
|
3380
|
+
"album:DATE_RECORDED": "originaldate",
|
|
3381
|
+
"album:DATE_RELEASED": "releasedate",
|
|
3382
|
+
"album:PART_NUMBER": "disk",
|
|
3383
|
+
"album:TOTAL_PARTS": "totaltracks",
|
|
3384
|
+
"track:ARTIST": "artist",
|
|
3385
|
+
"track:ARTISTSORT": "artistsort",
|
|
3386
|
+
"track:TITLE": "title",
|
|
3387
|
+
"track:PART_NUMBER": "track",
|
|
3388
|
+
"track:MUSICBRAINZ_TRACKID": "musicbrainz_recordingid",
|
|
3389
|
+
"track:MUSICBRAINZ_ALBUMID": "musicbrainz_albumid",
|
|
3390
|
+
"track:MUSICBRAINZ_ARTISTID": "musicbrainz_artistid",
|
|
3391
|
+
"track:PUBLISHER": "label",
|
|
3392
|
+
"track:GENRE": "genre",
|
|
3393
|
+
"track:ENCODER": "encodedby",
|
|
3394
|
+
"track:ENCODER_OPTIONS": "encodersettings",
|
|
3395
|
+
"edition:TOTAL_PARTS": "totaldiscs",
|
|
3396
|
+
picture: "picture"
|
|
3397
|
+
};
|
|
3398
|
+
var MatroskaTagMapper = class extends CaseInsensitiveTagMap {
|
|
3399
|
+
constructor() {
|
|
3400
|
+
super(["matroska"], ebmlTagMap);
|
|
3401
|
+
}
|
|
3402
|
+
};
|
|
3403
|
+
|
|
3404
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/aiff/AiffTagMap.js
|
|
3405
|
+
var tagMap = {
|
|
3406
|
+
NAME: "title",
|
|
3407
|
+
AUTH: "artist",
|
|
3408
|
+
"(c) ": "copyright",
|
|
3409
|
+
ANNO: "comment"
|
|
3410
|
+
};
|
|
3411
|
+
var AiffTagMapper = class extends CommonTagMapper {
|
|
3412
|
+
constructor() {
|
|
3413
|
+
super(["AIFF"], tagMap);
|
|
3414
|
+
}
|
|
3415
|
+
};
|
|
3416
|
+
|
|
3417
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/common/CombinedTagMapper.js
|
|
3418
|
+
var CombinedTagMapper = class {
|
|
3419
|
+
constructor() {
|
|
3420
|
+
this.tagMappers = {};
|
|
3421
|
+
[
|
|
3422
|
+
new ID3v1TagMapper(),
|
|
3423
|
+
new ID3v22TagMapper(),
|
|
3424
|
+
new ID3v24TagMapper(),
|
|
3425
|
+
new MP4TagMapper(),
|
|
3426
|
+
new MP4TagMapper(),
|
|
3427
|
+
new VorbisTagMapper(),
|
|
3428
|
+
new APEv2TagMapper(),
|
|
3429
|
+
new AsfTagMapper(),
|
|
3430
|
+
new RiffInfoTagMapper(),
|
|
3431
|
+
new MatroskaTagMapper(),
|
|
3432
|
+
new AiffTagMapper()
|
|
3433
|
+
].forEach((mapper) => {
|
|
3434
|
+
this.registerTagMapper(mapper);
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3437
|
+
/**
|
|
3438
|
+
* Convert native to generic (common) tags
|
|
3439
|
+
* @param tagType Originating tag format
|
|
3440
|
+
* @param tag Native tag to map to a generic tag id
|
|
3441
|
+
* @param warnings
|
|
3442
|
+
* @return Generic tag result (output of this function)
|
|
3443
|
+
*/
|
|
3444
|
+
mapTag(tagType2, tag, warnings) {
|
|
3445
|
+
const tagMapper = this.tagMappers[tagType2];
|
|
3446
|
+
if (tagMapper) {
|
|
3447
|
+
return this.tagMappers[tagType2].mapGenericTag(tag, warnings);
|
|
3448
|
+
}
|
|
3449
|
+
throw new InternalParserError(`No generic tag mapper defined for tag-format: ${tagType2}`);
|
|
3450
|
+
}
|
|
3451
|
+
registerTagMapper(genericTagMapper) {
|
|
3452
|
+
for (const tagType2 of genericTagMapper.tagTypes) {
|
|
3453
|
+
this.tagMappers[tagType2] = genericTagMapper;
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
};
|
|
3457
|
+
|
|
3458
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/lrc/LyricsParser.js
|
|
3459
|
+
var TIMESTAMP_REGEX = /\[(\d{2}):(\d{2})\.(\d{2,3})]/;
|
|
3460
|
+
function parseLyrics(input) {
|
|
3461
|
+
if (TIMESTAMP_REGEX.test(input)) {
|
|
3462
|
+
return parseLrc(input);
|
|
3463
|
+
}
|
|
3464
|
+
return toUnsyncedLyrics(input);
|
|
3465
|
+
}
|
|
3466
|
+
function toUnsyncedLyrics(lyrics) {
|
|
3467
|
+
return {
|
|
3468
|
+
contentType: LyricsContentType.lyrics,
|
|
3469
|
+
timeStampFormat: TimestampFormat.notSynchronized,
|
|
3470
|
+
text: lyrics.trim(),
|
|
3471
|
+
syncText: []
|
|
3472
|
+
};
|
|
3473
|
+
}
|
|
3474
|
+
function parseLrc(lrcString) {
|
|
3475
|
+
const lines = lrcString.split("\n");
|
|
3476
|
+
const syncText = [];
|
|
3477
|
+
for (const line of lines) {
|
|
3478
|
+
const match = line.match(TIMESTAMP_REGEX);
|
|
3479
|
+
if (match) {
|
|
3480
|
+
const minutes = Number.parseInt(match[1], 10);
|
|
3481
|
+
const seconds = Number.parseInt(match[2], 10);
|
|
3482
|
+
const ms = match[3].length === 3 ? Number.parseInt(match[3], 10) : Number.parseInt(match[3], 10) * 10;
|
|
3483
|
+
const timestamp = (minutes * 60 + seconds) * 1e3 + ms;
|
|
3484
|
+
const text = line.replace(TIMESTAMP_REGEX, "").trim();
|
|
3485
|
+
syncText.push({ timestamp, text });
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
return {
|
|
3489
|
+
contentType: LyricsContentType.lyrics,
|
|
3490
|
+
timeStampFormat: TimestampFormat.milliseconds,
|
|
3491
|
+
text: syncText.map((line) => line.text).join("\n"),
|
|
3492
|
+
syncText
|
|
3493
|
+
};
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/common/MetadataCollector.js
|
|
3497
|
+
var debug2 = (0, import_debug2.default)("music-metadata:collector");
|
|
3498
|
+
var TagPriority = ["matroska", "APEv2", "vorbis", "ID3v2.4", "ID3v2.3", "ID3v2.2", "exif", "asf", "iTunes", "AIFF", "ID3v1"];
|
|
3499
|
+
var MetadataCollector = class {
|
|
3500
|
+
constructor(opts) {
|
|
3501
|
+
this.format = {
|
|
3502
|
+
tagTypes: [],
|
|
3503
|
+
trackInfo: []
|
|
3504
|
+
};
|
|
3505
|
+
this.native = {};
|
|
3506
|
+
this.common = {
|
|
3507
|
+
track: { no: null, of: null },
|
|
3508
|
+
disk: { no: null, of: null },
|
|
3509
|
+
movementIndex: { no: null, of: null }
|
|
3510
|
+
};
|
|
3511
|
+
this.quality = {
|
|
3512
|
+
warnings: []
|
|
3513
|
+
};
|
|
3514
|
+
this.commonOrigin = {};
|
|
3515
|
+
this.originPriority = {};
|
|
3516
|
+
this.tagMapper = new CombinedTagMapper();
|
|
3517
|
+
this.opts = opts;
|
|
3518
|
+
let priority = 1;
|
|
3519
|
+
for (const tagType2 of TagPriority) {
|
|
3520
|
+
this.originPriority[tagType2] = priority++;
|
|
3521
|
+
}
|
|
3522
|
+
this.originPriority.artificial = 500;
|
|
3523
|
+
this.originPriority.id3v1 = 600;
|
|
3524
|
+
}
|
|
3525
|
+
/**
|
|
3526
|
+
* @returns {boolean} true if one or more tags have been found
|
|
3527
|
+
*/
|
|
3528
|
+
hasAny() {
|
|
3529
|
+
return Object.keys(this.native).length > 0;
|
|
3530
|
+
}
|
|
3531
|
+
addStreamInfo(streamInfo) {
|
|
3532
|
+
debug2(`streamInfo: type=${streamInfo.type ? TrackTypeValueToKeyMap[streamInfo.type] : "?"}, codec=${streamInfo.codecName}`);
|
|
3533
|
+
this.format.trackInfo.push(streamInfo);
|
|
3534
|
+
}
|
|
3535
|
+
setFormat(key, value) {
|
|
3536
|
+
debug2(`format: ${key} = ${value}`);
|
|
3537
|
+
this.format[key] = value;
|
|
3538
|
+
if (this.opts?.observer) {
|
|
3539
|
+
this.opts.observer({ metadata: this, tag: { type: "format", id: key, value } });
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
setAudioOnly() {
|
|
3543
|
+
this.setFormat("hasAudio", true);
|
|
3544
|
+
this.setFormat("hasVideo", false);
|
|
3545
|
+
}
|
|
3546
|
+
async addTag(tagType2, tagId, value) {
|
|
3547
|
+
debug2(`tag ${tagType2}.${tagId} = ${value}`);
|
|
3548
|
+
if (!this.native[tagType2]) {
|
|
3549
|
+
this.format.tagTypes.push(tagType2);
|
|
3550
|
+
this.native[tagType2] = [];
|
|
3551
|
+
}
|
|
3552
|
+
this.native[tagType2].push({ id: tagId, value });
|
|
3553
|
+
await this.toCommon(tagType2, tagId, value);
|
|
3554
|
+
}
|
|
3555
|
+
addWarning(warning) {
|
|
3556
|
+
this.quality.warnings.push({ message: warning });
|
|
3557
|
+
}
|
|
3558
|
+
async postMap(tagType2, tag) {
|
|
3559
|
+
switch (tag.id) {
|
|
3560
|
+
case "artist":
|
|
3561
|
+
return this.handleSingularArtistTag(tagType2, tag, "artist", "artists");
|
|
3562
|
+
case "albumartist":
|
|
3563
|
+
return this.handleSingularArtistTag(tagType2, tag, "albumartist", "albumartists");
|
|
3564
|
+
case "artists":
|
|
3565
|
+
return this.handlePluralArtistTag(tagType2, tag, "artist", "artists");
|
|
3566
|
+
case "albumartists":
|
|
3567
|
+
return this.handlePluralArtistTag(tagType2, tag, "albumartist", "albumartists");
|
|
3568
|
+
case "picture":
|
|
3569
|
+
return this.postFixPicture(tag.value).then((picture) => {
|
|
3570
|
+
if (picture !== null) {
|
|
3571
|
+
tag.value = picture;
|
|
3572
|
+
this.setGenericTag(tagType2, tag);
|
|
3573
|
+
}
|
|
3574
|
+
});
|
|
3575
|
+
case "totaltracks":
|
|
3576
|
+
this.common.track.of = CommonTagMapper.toIntOrNull(tag.value);
|
|
3577
|
+
return;
|
|
3578
|
+
case "totaldiscs":
|
|
3579
|
+
this.common.disk.of = CommonTagMapper.toIntOrNull(tag.value);
|
|
3580
|
+
return;
|
|
3581
|
+
case "movementTotal":
|
|
3582
|
+
this.common.movementIndex.of = CommonTagMapper.toIntOrNull(tag.value);
|
|
3583
|
+
return;
|
|
3584
|
+
case "track":
|
|
3585
|
+
case "disk":
|
|
3586
|
+
case "movementIndex": {
|
|
3587
|
+
const of = this.common[tag.id].of;
|
|
3588
|
+
this.common[tag.id] = CommonTagMapper.normalizeTrack(tag.value);
|
|
3589
|
+
this.common[tag.id].of = of != null ? of : this.common[tag.id].of;
|
|
3590
|
+
return;
|
|
3591
|
+
}
|
|
3592
|
+
case "bpm":
|
|
3593
|
+
case "year":
|
|
3594
|
+
case "originalyear":
|
|
3595
|
+
tag.value = Number.parseInt(tag.value, 10);
|
|
3596
|
+
break;
|
|
3597
|
+
case "date": {
|
|
3598
|
+
const year = Number.parseInt(tag.value.substr(0, 4), 10);
|
|
3599
|
+
if (!Number.isNaN(year)) {
|
|
3600
|
+
this.common.year = year;
|
|
3601
|
+
}
|
|
3602
|
+
break;
|
|
3603
|
+
}
|
|
3604
|
+
case "discogs_label_id":
|
|
3605
|
+
case "discogs_release_id":
|
|
3606
|
+
case "discogs_master_release_id":
|
|
3607
|
+
case "discogs_artist_id":
|
|
3608
|
+
case "discogs_votes":
|
|
3609
|
+
tag.value = typeof tag.value === "string" ? Number.parseInt(tag.value, 10) : tag.value;
|
|
3610
|
+
break;
|
|
3611
|
+
case "replaygain_track_gain":
|
|
3612
|
+
case "replaygain_track_peak":
|
|
3613
|
+
case "replaygain_album_gain":
|
|
3614
|
+
case "replaygain_album_peak":
|
|
3615
|
+
tag.value = toRatio(tag.value);
|
|
3616
|
+
break;
|
|
3617
|
+
case "replaygain_track_minmax":
|
|
3618
|
+
tag.value = tag.value.split(",").map((v) => Number.parseInt(v, 10));
|
|
3619
|
+
break;
|
|
3620
|
+
case "replaygain_undo": {
|
|
3621
|
+
const minMix = tag.value.split(",").map((v) => Number.parseInt(v, 10));
|
|
3622
|
+
tag.value = {
|
|
3623
|
+
leftChannel: minMix[0],
|
|
3624
|
+
rightChannel: minMix[1]
|
|
3625
|
+
};
|
|
3626
|
+
break;
|
|
3627
|
+
}
|
|
3628
|
+
case "gapless":
|
|
3629
|
+
// iTunes gap-less flag
|
|
3630
|
+
case "compilation":
|
|
3631
|
+
case "podcast":
|
|
3632
|
+
case "showMovement":
|
|
3633
|
+
tag.value = tag.value === "1" || tag.value === 1;
|
|
3634
|
+
break;
|
|
3635
|
+
case "isrc": {
|
|
3636
|
+
const commonTag = this.common[tag.id];
|
|
3637
|
+
if (commonTag && commonTag.indexOf(tag.value) !== -1)
|
|
3638
|
+
return;
|
|
3639
|
+
break;
|
|
3640
|
+
}
|
|
3641
|
+
case "comment":
|
|
3642
|
+
if (typeof tag.value === "string") {
|
|
3643
|
+
tag.value = { text: tag.value };
|
|
3644
|
+
}
|
|
3645
|
+
if (tag.value.descriptor === "iTunPGAP") {
|
|
3646
|
+
this.setGenericTag(tagType2, { id: "gapless", value: tag.value.text === "1" });
|
|
3647
|
+
}
|
|
3648
|
+
break;
|
|
3649
|
+
case "lyrics":
|
|
3650
|
+
if (typeof tag.value === "string") {
|
|
3651
|
+
tag.value = parseLyrics(tag.value);
|
|
3652
|
+
}
|
|
3653
|
+
break;
|
|
3654
|
+
default:
|
|
3655
|
+
}
|
|
3656
|
+
if (tag.value !== null) {
|
|
3657
|
+
this.setGenericTag(tagType2, tag);
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
/**
|
|
3661
|
+
* Convert native tags to common tags
|
|
3662
|
+
* @returns {IAudioMetadata} Native + common tags
|
|
3663
|
+
*/
|
|
3664
|
+
toCommonMetadata() {
|
|
3665
|
+
return {
|
|
3666
|
+
format: this.format,
|
|
3667
|
+
native: this.native,
|
|
3668
|
+
quality: this.quality,
|
|
3669
|
+
common: this.common
|
|
3670
|
+
};
|
|
3671
|
+
}
|
|
3672
|
+
/**
|
|
3673
|
+
* Handle singular artist tags (artist, albumartist) and cross-populate to plural form
|
|
3674
|
+
*/
|
|
3675
|
+
handleSingularArtistTag(tagType2, tag, singularId, pluralId) {
|
|
3676
|
+
if (this.commonOrigin[singularId] === this.originPriority[tagType2]) {
|
|
3677
|
+
return this.postMap("artificial", { id: pluralId, value: tag.value });
|
|
3678
|
+
}
|
|
3679
|
+
if (!this.common[pluralId]) {
|
|
3680
|
+
this.setGenericTag("artificial", { id: pluralId, value: tag.value });
|
|
3681
|
+
}
|
|
3682
|
+
this.setGenericTag(tagType2, tag);
|
|
3683
|
+
}
|
|
3684
|
+
/**
|
|
3685
|
+
* Handle plural artist tags (artists, albumartists) and cross-populate to singular form
|
|
3686
|
+
*/
|
|
3687
|
+
handlePluralArtistTag(tagType2, tag, singularId, pluralId) {
|
|
3688
|
+
if (!this.common[singularId] || this.commonOrigin[singularId] === this.originPriority.artificial) {
|
|
3689
|
+
if (!this.common[pluralId] || this.common[pluralId].indexOf(tag.value) === -1) {
|
|
3690
|
+
const values = (this.common[pluralId] || []).concat([tag.value]);
|
|
3691
|
+
const value = joinArtists(values);
|
|
3692
|
+
this.setGenericTag("artificial", { id: singularId, value });
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3695
|
+
this.setGenericTag(tagType2, tag);
|
|
3696
|
+
}
|
|
3697
|
+
/**
|
|
3698
|
+
* Fix some common issues with picture object
|
|
3699
|
+
* @param picture Picture
|
|
3700
|
+
*/
|
|
3701
|
+
async postFixPicture(picture) {
|
|
3702
|
+
if (picture.data && picture.data.length > 0) {
|
|
3703
|
+
if (!picture.format) {
|
|
3704
|
+
const fileType = await fileTypeFromBuffer(Uint8Array.from(picture.data));
|
|
3705
|
+
if (fileType) {
|
|
3706
|
+
picture.format = fileType.mime;
|
|
3707
|
+
} else {
|
|
3708
|
+
return null;
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
picture.format = picture.format.toLocaleLowerCase();
|
|
3712
|
+
switch (picture.format) {
|
|
3713
|
+
case "image/jpg":
|
|
3714
|
+
picture.format = "image/jpeg";
|
|
3715
|
+
}
|
|
3716
|
+
return picture;
|
|
3717
|
+
}
|
|
3718
|
+
this.addWarning("Empty picture tag found");
|
|
3719
|
+
return null;
|
|
3720
|
+
}
|
|
3721
|
+
/**
|
|
3722
|
+
* Convert native tag to common tags
|
|
3723
|
+
*/
|
|
3724
|
+
async toCommon(tagType2, tagId, value) {
|
|
3725
|
+
const tag = { id: tagId, value };
|
|
3726
|
+
const genericTag = this.tagMapper.mapTag(tagType2, tag, this);
|
|
3727
|
+
if (genericTag) {
|
|
3728
|
+
await this.postMap(tagType2, genericTag);
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
/**
|
|
3732
|
+
* Set generic tag
|
|
3733
|
+
*/
|
|
3734
|
+
setGenericTag(tagType2, tag) {
|
|
3735
|
+
debug2(`common.${tag.id} = ${tag.value}`);
|
|
3736
|
+
const prio0 = this.commonOrigin[tag.id] || 1e3;
|
|
3737
|
+
const prio1 = this.originPriority[tagType2];
|
|
3738
|
+
if (isSingleton(tag.id)) {
|
|
3739
|
+
if (prio1 <= prio0) {
|
|
3740
|
+
this.common[tag.id] = tag.value;
|
|
3741
|
+
this.commonOrigin[tag.id] = prio1;
|
|
3742
|
+
} else {
|
|
3743
|
+
return debug2(`Ignore native tag (singleton): ${tagType2}.${tag.id} = ${tag.value}`);
|
|
3744
|
+
}
|
|
3745
|
+
} else {
|
|
3746
|
+
if (prio1 === prio0) {
|
|
3747
|
+
if (!isUnique(tag.id) || this.common[tag.id].indexOf(tag.value) === -1) {
|
|
3748
|
+
this.common[tag.id].push(tag.value);
|
|
3749
|
+
} else {
|
|
3750
|
+
debug2(`Ignore duplicate value: ${tagType2}.${tag.id} = ${tag.value}`);
|
|
3751
|
+
}
|
|
3752
|
+
} else if (prio1 < prio0) {
|
|
3753
|
+
this.common[tag.id] = [tag.value];
|
|
3754
|
+
this.commonOrigin[tag.id] = prio1;
|
|
3755
|
+
} else {
|
|
3756
|
+
return debug2(`Ignore native tag (list): ${tagType2}.${tag.id} = ${tag.value}`);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
if (this.opts?.observer) {
|
|
3760
|
+
this.opts.observer({ metadata: this, tag: { type: "common", id: tag.id, value: tag.value } });
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
};
|
|
3764
|
+
function joinArtists(artists) {
|
|
3765
|
+
if (artists.length > 2) {
|
|
3766
|
+
return `${artists.slice(0, artists.length - 1).join(", ")} & ${artists[artists.length - 1]}`;
|
|
3767
|
+
}
|
|
3768
|
+
return artists.join(" & ");
|
|
3769
|
+
}
|
|
3770
|
+
|
|
3771
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/mpeg/MpegLoader.js
|
|
3772
|
+
var mpegParserLoader = {
|
|
3773
|
+
parserType: "mpeg",
|
|
3774
|
+
extensions: [".mp2", ".mp3", ".m2a", ".aac", "aacp"],
|
|
3775
|
+
mimeTypes: ["audio/mpeg", "audio/mp3", "audio/aacs", "audio/aacp"],
|
|
3776
|
+
async load() {
|
|
3777
|
+
return (await import("./MpegParser-PXKEUF2B.js")).MpegParser;
|
|
3778
|
+
}
|
|
3779
|
+
};
|
|
3780
|
+
|
|
3781
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/apev2/Apev2Loader.js
|
|
3782
|
+
var apeParserLoader = {
|
|
3783
|
+
parserType: "apev2",
|
|
3784
|
+
extensions: [".ape"],
|
|
3785
|
+
mimeTypes: ["audio/ape", "audio/monkeys-audio"],
|
|
3786
|
+
async load() {
|
|
3787
|
+
return (await import("./APEv2Parser-EU45AV6X.js")).APEv2Parser;
|
|
3788
|
+
}
|
|
3789
|
+
};
|
|
3790
|
+
|
|
3791
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/asf/AsfLoader.js
|
|
3792
|
+
var asfParserLoader = {
|
|
3793
|
+
parserType: "asf",
|
|
3794
|
+
extensions: [".asf"],
|
|
3795
|
+
mimeTypes: ["audio/ms-wma", "video/ms-wmv", "audio/ms-asf", "video/ms-asf", "application/vnd.ms-asf"],
|
|
3796
|
+
async load() {
|
|
3797
|
+
return (await import("./AsfParser-HD5CSGIO.js")).AsfParser;
|
|
3798
|
+
}
|
|
3799
|
+
};
|
|
3800
|
+
|
|
3801
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/dsdiff/DsdiffLoader.js
|
|
3802
|
+
var dsdiffParserLoader = {
|
|
3803
|
+
parserType: "dsdiff",
|
|
3804
|
+
extensions: [".dff"],
|
|
3805
|
+
mimeTypes: ["audio/dsf", "audio/dsd"],
|
|
3806
|
+
async load() {
|
|
3807
|
+
return (await import("./DsdiffParser-OJREDMBI.js")).DsdiffParser;
|
|
3808
|
+
}
|
|
3809
|
+
};
|
|
3810
|
+
|
|
3811
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/aiff/AiffLoader.js
|
|
3812
|
+
var aiffParserLoader = {
|
|
3813
|
+
parserType: "aiff",
|
|
3814
|
+
extensions: [".aif", "aiff", "aifc"],
|
|
3815
|
+
mimeTypes: ["audio/aiff", "audio/aif", "audio/aifc", "application/aiff"],
|
|
3816
|
+
async load() {
|
|
3817
|
+
return (await import("./AiffParser-FOX7GQ42.js")).AIFFParser;
|
|
3818
|
+
}
|
|
3819
|
+
};
|
|
3820
|
+
|
|
3821
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/dsf/DsfLoader.js
|
|
3822
|
+
var dsfParserLoader = {
|
|
3823
|
+
parserType: "dsf",
|
|
3824
|
+
extensions: [".dsf"],
|
|
3825
|
+
mimeTypes: ["audio/dsf"],
|
|
3826
|
+
async load() {
|
|
3827
|
+
return (await import("./DsfParser-2YL4ARJ7.js")).DsfParser;
|
|
3828
|
+
}
|
|
3829
|
+
};
|
|
3830
|
+
|
|
3831
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/flac/FlacLoader.js
|
|
3832
|
+
var flacParserLoader = {
|
|
3833
|
+
parserType: "flac",
|
|
3834
|
+
extensions: [".flac"],
|
|
3835
|
+
mimeTypes: ["audio/flac"],
|
|
3836
|
+
async load() {
|
|
3837
|
+
return (await import("./FlacParser-IVV4RYF6.js")).FlacParser;
|
|
3838
|
+
}
|
|
3839
|
+
};
|
|
3840
|
+
|
|
3841
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/matroska/MatroskaLoader.js
|
|
3842
|
+
var matroskaParserLoader = {
|
|
3843
|
+
parserType: "matroska",
|
|
3844
|
+
extensions: [".mka", ".mkv", ".mk3d", ".mks", "webm"],
|
|
3845
|
+
mimeTypes: ["audio/matroska", "video/matroska", "audio/webm", "video/webm"],
|
|
3846
|
+
async load() {
|
|
3847
|
+
return (await import("./MatroskaParser-4OEK43GF.js")).MatroskaParser;
|
|
3848
|
+
}
|
|
3849
|
+
};
|
|
3850
|
+
|
|
3851
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/mp4/Mp4Loader.js
|
|
3852
|
+
var mp4ParserLoader = {
|
|
3853
|
+
parserType: "mp4",
|
|
3854
|
+
extensions: [".mp4", ".m4a", ".m4b", ".m4pa", "m4v", "m4r", "3gp", ".mov", ".movie", ".qt"],
|
|
3855
|
+
mimeTypes: ["audio/mp4", "audio/m4a", "video/m4v", "video/mp4", "video/quicktime"],
|
|
3856
|
+
async load() {
|
|
3857
|
+
return (await import("./MP4Parser-NLX4A2YN.js")).MP4Parser;
|
|
3858
|
+
}
|
|
3859
|
+
};
|
|
3860
|
+
|
|
3861
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/musepack/MusepackLoader.js
|
|
3862
|
+
var musepackParserLoader = {
|
|
3863
|
+
parserType: "musepack",
|
|
3864
|
+
extensions: [".mpc"],
|
|
3865
|
+
mimeTypes: ["audio/musepack"],
|
|
3866
|
+
async load() {
|
|
3867
|
+
return (await import("./MusepackParser-54QGYRLY.js")).MusepackParser;
|
|
3868
|
+
}
|
|
3869
|
+
};
|
|
3870
|
+
|
|
3871
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/ogg/OggLoader.js
|
|
3872
|
+
var oggParserLoader = {
|
|
3873
|
+
parserType: "ogg",
|
|
3874
|
+
extensions: [".ogg", ".ogv", ".oga", ".ogm", ".ogx", ".opus", ".spx"],
|
|
3875
|
+
mimeTypes: ["audio/ogg", "audio/opus", "audio/speex", "video/ogg"],
|
|
3876
|
+
// RFC 7845, RFC 6716, RFC 5574
|
|
3877
|
+
async load() {
|
|
3878
|
+
return (await import("./OggParser-KRV5QCGZ.js")).OggParser;
|
|
3879
|
+
}
|
|
3880
|
+
};
|
|
3881
|
+
|
|
3882
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/wavpack/WavPackLoader.js
|
|
3883
|
+
var wavpackParserLoader = {
|
|
3884
|
+
parserType: "wavpack",
|
|
3885
|
+
extensions: [".wv", ".wvp"],
|
|
3886
|
+
mimeTypes: ["audio/wavpack"],
|
|
3887
|
+
async load() {
|
|
3888
|
+
return (await import("./WavPackParser-XPZSQFVS.js")).WavPackParser;
|
|
3889
|
+
}
|
|
3890
|
+
};
|
|
3891
|
+
|
|
3892
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/wav/WaveLoader.js
|
|
3893
|
+
var riffParserLoader = {
|
|
3894
|
+
parserType: "riff",
|
|
3895
|
+
extensions: [".wav", "wave", ".bwf"],
|
|
3896
|
+
mimeTypes: ["audio/vnd.wave", "audio/wav", "audio/wave"],
|
|
3897
|
+
async load() {
|
|
3898
|
+
return (await import("./WaveParser-27IS2RAI.js")).WaveParser;
|
|
3899
|
+
}
|
|
3900
|
+
};
|
|
3901
|
+
|
|
3902
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/ParserFactory.js
|
|
3903
|
+
var debug3 = (0, import_debug3.default)("music-metadata:parser:factory");
|
|
3904
|
+
function parseHttpContentType(contentType) {
|
|
3905
|
+
const type = import_content_type.default.parse(contentType);
|
|
3906
|
+
const mime = (0, import_media_typer.parse)(type.type);
|
|
3907
|
+
return {
|
|
3908
|
+
type: mime.type,
|
|
3909
|
+
subtype: mime.subtype,
|
|
3910
|
+
suffix: mime.suffix,
|
|
3911
|
+
parameters: type.parameters
|
|
3912
|
+
};
|
|
3913
|
+
}
|
|
3914
|
+
var ParserFactory = class {
|
|
3915
|
+
constructor() {
|
|
3916
|
+
this.parsers = [];
|
|
3917
|
+
[
|
|
3918
|
+
flacParserLoader,
|
|
3919
|
+
mpegParserLoader,
|
|
3920
|
+
apeParserLoader,
|
|
3921
|
+
mp4ParserLoader,
|
|
3922
|
+
matroskaParserLoader,
|
|
3923
|
+
riffParserLoader,
|
|
3924
|
+
oggParserLoader,
|
|
3925
|
+
asfParserLoader,
|
|
3926
|
+
aiffParserLoader,
|
|
3927
|
+
wavpackParserLoader,
|
|
3928
|
+
musepackParserLoader,
|
|
3929
|
+
dsfParserLoader,
|
|
3930
|
+
dsdiffParserLoader
|
|
3931
|
+
].forEach((parser) => {
|
|
3932
|
+
this.registerParser(parser);
|
|
3933
|
+
});
|
|
3934
|
+
}
|
|
3935
|
+
registerParser(parser) {
|
|
3936
|
+
this.parsers.push(parser);
|
|
3937
|
+
}
|
|
3938
|
+
async parse(tokenizer, parserLoader, opts) {
|
|
3939
|
+
if (tokenizer.supportsRandomAccess()) {
|
|
3940
|
+
debug3("tokenizer supports random-access, scanning for appending headers");
|
|
3941
|
+
await scanAppendingHeaders(tokenizer, opts);
|
|
3942
|
+
} else {
|
|
3943
|
+
debug3("tokenizer does not support random-access, cannot scan for appending headers");
|
|
3944
|
+
}
|
|
3945
|
+
if (!parserLoader) {
|
|
3946
|
+
const buf = new Uint8Array(4100);
|
|
3947
|
+
if (tokenizer.fileInfo.mimeType) {
|
|
3948
|
+
parserLoader = this.findLoaderForContentType(tokenizer.fileInfo.mimeType);
|
|
3949
|
+
}
|
|
3950
|
+
if (!parserLoader && tokenizer.fileInfo.path) {
|
|
3951
|
+
parserLoader = this.findLoaderForExtension(tokenizer.fileInfo.path);
|
|
3952
|
+
}
|
|
3953
|
+
if (!parserLoader) {
|
|
3954
|
+
debug3("Guess parser on content...");
|
|
3955
|
+
await tokenizer.peekBuffer(buf, { mayBeLess: true });
|
|
3956
|
+
const guessedType = await fileTypeFromBuffer(buf, { mpegOffsetTolerance: 10 });
|
|
3957
|
+
if (!guessedType || !guessedType.mime) {
|
|
3958
|
+
throw new CouldNotDetermineFileTypeError("Failed to determine audio format");
|
|
3959
|
+
}
|
|
3960
|
+
debug3(`Guessed file type is mime=${guessedType.mime}, extension=${guessedType.ext}`);
|
|
3961
|
+
parserLoader = this.findLoaderForContentType(guessedType.mime);
|
|
3962
|
+
if (!parserLoader) {
|
|
3963
|
+
throw new UnsupportedFileTypeError(`Guessed MIME-type not supported: ${guessedType.mime}`);
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
debug3(`Loading ${parserLoader.parserType} parser...`);
|
|
3968
|
+
const metadata = new MetadataCollector(opts);
|
|
3969
|
+
const ParserImpl = await parserLoader.load();
|
|
3970
|
+
const parser = new ParserImpl(metadata, tokenizer, opts ?? {});
|
|
3971
|
+
debug3(`Parser ${parserLoader.parserType} loaded`);
|
|
3972
|
+
await parser.parse();
|
|
3973
|
+
if (metadata.format.trackInfo) {
|
|
3974
|
+
if (metadata.format.hasAudio === void 0) {
|
|
3975
|
+
metadata.setFormat("hasAudio", !!metadata.format.trackInfo.find((track) => track.type === TrackType.audio));
|
|
3976
|
+
}
|
|
3977
|
+
if (metadata.format.hasVideo === void 0) {
|
|
3978
|
+
metadata.setFormat("hasVideo", !!metadata.format.trackInfo.find((track) => track.type === TrackType.video));
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
return metadata.toCommonMetadata();
|
|
3982
|
+
}
|
|
3983
|
+
/**
|
|
3984
|
+
* @param filePath - Path, filename or extension to audio file
|
|
3985
|
+
* @return Parser submodule name
|
|
3986
|
+
*/
|
|
3987
|
+
findLoaderForExtension(filePath) {
|
|
3988
|
+
if (!filePath)
|
|
3989
|
+
return;
|
|
3990
|
+
const extension = getExtension(filePath).toLocaleLowerCase() || filePath;
|
|
3991
|
+
return this.parsers.find((parser) => parser.extensions.indexOf(extension) !== -1);
|
|
3992
|
+
}
|
|
3993
|
+
findLoaderForContentType(httpContentType) {
|
|
3994
|
+
let mime;
|
|
3995
|
+
if (!httpContentType)
|
|
3996
|
+
return;
|
|
3997
|
+
try {
|
|
3998
|
+
mime = parseHttpContentType(httpContentType);
|
|
3999
|
+
} catch (_err) {
|
|
4000
|
+
debug3(`Invalid HTTP Content-Type header value: ${httpContentType}`);
|
|
4001
|
+
return;
|
|
4002
|
+
}
|
|
4003
|
+
const subType = mime.subtype.indexOf("x-") === 0 ? mime.subtype.substring(2) : mime.subtype;
|
|
4004
|
+
return this.parsers.find((parser) => parser.mimeTypes.find((loader) => loader.indexOf(`${mime.type}/${subType}`) !== -1));
|
|
4005
|
+
}
|
|
4006
|
+
getSupportedMimeTypes() {
|
|
4007
|
+
const mimeTypeSet = /* @__PURE__ */ new Set();
|
|
4008
|
+
this.parsers.forEach((loader) => {
|
|
4009
|
+
loader.mimeTypes.forEach((mimeType) => {
|
|
4010
|
+
mimeTypeSet.add(mimeType);
|
|
4011
|
+
mimeTypeSet.add(mimeType.replace("/", "/x-"));
|
|
4012
|
+
});
|
|
4013
|
+
});
|
|
4014
|
+
return Array.from(mimeTypeSet);
|
|
4015
|
+
}
|
|
4016
|
+
};
|
|
4017
|
+
function getExtension(fname) {
|
|
4018
|
+
const i = fname.lastIndexOf(".");
|
|
4019
|
+
return i === -1 ? "" : fname.substring(i);
|
|
4020
|
+
}
|
|
4021
|
+
|
|
4022
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/lyrics3/Lyrics3.js
|
|
4023
|
+
var endTag2 = "LYRICS200";
|
|
4024
|
+
async function getLyricsHeaderLength(tokenizer) {
|
|
4025
|
+
const fileSize = tokenizer.fileInfo.size;
|
|
4026
|
+
if (fileSize >= 143) {
|
|
4027
|
+
const buf = new Uint8Array(15);
|
|
4028
|
+
const position = tokenizer.position;
|
|
4029
|
+
await tokenizer.readBuffer(buf, { position: fileSize - 143 });
|
|
4030
|
+
tokenizer.setPosition(position);
|
|
4031
|
+
const txt = textDecode(buf, "latin1");
|
|
4032
|
+
const tag = txt.substring(6);
|
|
4033
|
+
if (tag === endTag2) {
|
|
4034
|
+
return Number.parseInt(txt.substring(0, 6), 10) + 15;
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
return 0;
|
|
4038
|
+
}
|
|
4039
|
+
|
|
4040
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/core.js
|
|
4041
|
+
async function parseBlob(blob, options = {}) {
|
|
4042
|
+
const tokenizer = fromBlob(blob);
|
|
4043
|
+
try {
|
|
4044
|
+
return await parseFromTokenizer(tokenizer, options);
|
|
4045
|
+
} finally {
|
|
4046
|
+
await tokenizer.close();
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
async function parseWebStream(webStream, fileInfo, options = {}) {
|
|
4050
|
+
const tokenizer = fromWebStream(webStream, { fileInfo: typeof fileInfo === "string" ? { mimeType: fileInfo } : fileInfo });
|
|
4051
|
+
try {
|
|
4052
|
+
return await parseFromTokenizer(tokenizer, options);
|
|
4053
|
+
} finally {
|
|
4054
|
+
await tokenizer.close();
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
async function parseBuffer(uint8Array, fileInfo, options = {}) {
|
|
4058
|
+
const tokenizer = fromBuffer(uint8Array, { fileInfo: typeof fileInfo === "string" ? { mimeType: fileInfo } : fileInfo });
|
|
4059
|
+
return parseFromTokenizer(tokenizer, options);
|
|
4060
|
+
}
|
|
4061
|
+
function parseFromTokenizer(tokenizer, options) {
|
|
4062
|
+
const parserFactory = new ParserFactory();
|
|
4063
|
+
return parserFactory.parse(tokenizer, void 0, options);
|
|
4064
|
+
}
|
|
4065
|
+
function orderTags(nativeTags) {
|
|
4066
|
+
const tags = {};
|
|
4067
|
+
for (const { id, value } of nativeTags) {
|
|
4068
|
+
(tags[id] || (tags[id] = [])).push(value);
|
|
4069
|
+
}
|
|
4070
|
+
return tags;
|
|
4071
|
+
}
|
|
4072
|
+
function ratingToStars(rating) {
|
|
4073
|
+
return rating === void 0 ? 0 : 1 + Math.round(rating * 4);
|
|
4074
|
+
}
|
|
4075
|
+
function selectCover(pictures) {
|
|
4076
|
+
return pictures ? pictures.reduce((acc, cur) => {
|
|
4077
|
+
if (cur.name && cur.name.toLowerCase() in ["front", "cover", "cover (front)"])
|
|
4078
|
+
return cur;
|
|
4079
|
+
return acc;
|
|
4080
|
+
}) : null;
|
|
4081
|
+
}
|
|
4082
|
+
async function scanAppendingHeaders(tokenizer, options = {}) {
|
|
4083
|
+
let apeOffset = tokenizer.fileInfo.size;
|
|
4084
|
+
if (await hasID3v1Header(tokenizer)) {
|
|
4085
|
+
apeOffset -= 128;
|
|
4086
|
+
const lyricsLen = await getLyricsHeaderLength(tokenizer);
|
|
4087
|
+
apeOffset -= lyricsLen;
|
|
4088
|
+
}
|
|
4089
|
+
options.apeHeader = await APEv2Parser.findApeFooterOffset(tokenizer, apeOffset);
|
|
4090
|
+
}
|
|
4091
|
+
function getSupportedMimeTypes() {
|
|
4092
|
+
return new ParserFactory().getSupportedMimeTypes();
|
|
4093
|
+
}
|
|
4094
|
+
|
|
4095
|
+
// ../../node_modules/.pnpm/music-metadata@11.12.0/node_modules/music-metadata/lib/index.js
|
|
4096
|
+
var debug4 = (0, import_debug4.default)("music-metadata:parser");
|
|
4097
|
+
async function parseStream(stream, fileInfo, options = {}) {
|
|
4098
|
+
const tokenizer = await fromStream(stream, { fileInfo: typeof fileInfo === "string" ? { mimeType: fileInfo } : fileInfo });
|
|
4099
|
+
try {
|
|
4100
|
+
return await parseFromTokenizer(tokenizer, options);
|
|
4101
|
+
} finally {
|
|
4102
|
+
await tokenizer.close();
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
async function parseFile(filePath, options = {}) {
|
|
4106
|
+
debug4(`parseFile: ${filePath}`);
|
|
4107
|
+
const fileTokenizer = await fromFile(filePath);
|
|
4108
|
+
const parserFactory = new ParserFactory();
|
|
4109
|
+
try {
|
|
4110
|
+
const parserLoader = parserFactory.findLoaderForExtension(filePath);
|
|
4111
|
+
if (!parserLoader)
|
|
4112
|
+
debug4("Parser could not be determined by file extension");
|
|
4113
|
+
try {
|
|
4114
|
+
return await parserFactory.parse(fileTokenizer, parserLoader, options);
|
|
4115
|
+
} catch (error) {
|
|
4116
|
+
if (error instanceof CouldNotDetermineFileTypeError || error instanceof UnsupportedFileTypeError) {
|
|
4117
|
+
error.message += `: ${filePath}`;
|
|
4118
|
+
}
|
|
4119
|
+
throw error;
|
|
4120
|
+
}
|
|
4121
|
+
} finally {
|
|
4122
|
+
await fileTokenizer.close();
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
export {
|
|
4126
|
+
CouldNotDetermineFileTypeError,
|
|
4127
|
+
FieldDecodingError,
|
|
4128
|
+
InternalParserError,
|
|
4129
|
+
LyricsContentType,
|
|
4130
|
+
TimestampFormat,
|
|
4131
|
+
UnsupportedFileTypeError,
|
|
4132
|
+
getSupportedMimeTypes,
|
|
4133
|
+
makeParseError,
|
|
4134
|
+
makeUnexpectedFileContentError,
|
|
4135
|
+
orderTags,
|
|
4136
|
+
parseBlob,
|
|
4137
|
+
parseBuffer,
|
|
4138
|
+
parseFile,
|
|
4139
|
+
parseFromTokenizer,
|
|
4140
|
+
parseStream,
|
|
4141
|
+
parseWebStream,
|
|
4142
|
+
ratingToStars,
|
|
4143
|
+
scanAppendingHeaders,
|
|
4144
|
+
selectCover
|
|
4145
|
+
};
|
|
4146
|
+
/*! Bundled license information:
|
|
4147
|
+
|
|
4148
|
+
content-type/index.js:
|
|
4149
|
+
(*!
|
|
4150
|
+
* content-type
|
|
4151
|
+
* Copyright(c) 2015 Douglas Christopher Wilson
|
|
4152
|
+
* MIT Licensed
|
|
4153
|
+
*)
|
|
4154
|
+
|
|
4155
|
+
media-typer/index.js:
|
|
4156
|
+
(*!
|
|
4157
|
+
* media-typer
|
|
4158
|
+
* Copyright(c) 2014-2017 Douglas Christopher Wilson
|
|
4159
|
+
* MIT Licensed
|
|
4160
|
+
*)
|
|
4161
|
+
*/
|