taglib-wasm 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +512 -38
- package/dist/index.browser.js +275 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/simple.browser.js +275 -3
- package/dist/src/bwf/bext.d.ts +28 -0
- package/dist/src/bwf/bext.d.ts.map +1 -0
- package/dist/src/bwf/bext.js +126 -0
- package/dist/src/msgpack/encoder.d.ts.map +1 -1
- package/dist/src/msgpack/encoder.js +9 -1
- package/dist/src/runtime/unified-loader/module-loading.js +1 -1
- package/dist/src/runtime/wasi-adapter/file-handle.d.ts +7 -1
- package/dist/src/runtime/wasi-adapter/file-handle.d.ts.map +1 -1
- package/dist/src/runtime/wasi-adapter/file-handle.js +41 -2
- package/dist/src/runtime/wasi-host-loader.d.ts +1 -1
- package/dist/src/runtime/wasi-host-loader.js +1 -1
- package/dist/src/taglib/audio-file-bwf.d.ts +14 -0
- package/dist/src/taglib/audio-file-bwf.d.ts.map +1 -0
- package/dist/src/taglib/audio-file-bwf.js +41 -0
- package/dist/src/taglib/audio-file-impl.d.ts +10 -0
- package/dist/src/taglib/audio-file-impl.d.ts.map +1 -1
- package/dist/src/taglib/audio-file-impl.js +65 -1
- package/dist/src/taglib/audio-file-interface.d.ts +27 -0
- package/dist/src/taglib/audio-file-interface.d.ts.map +1 -1
- package/dist/src/taglib/embind-adapter.d.ts +2 -0
- package/dist/src/taglib/embind-adapter.d.ts.map +1 -1
- package/dist/src/taglib/embind-adapter.js +27 -2
- package/dist/src/types/audio-formats.d.ts +18 -0
- package/dist/src/types/audio-formats.d.ts.map +1 -1
- package/dist/src/types/bwf.d.ts +43 -0
- package/dist/src/types/bwf.d.ts.map +1 -0
- package/dist/src/types/bwf.js +0 -0
- package/dist/src/types/chapters.d.ts +47 -0
- package/dist/src/types/chapters.d.ts.map +1 -0
- package/dist/src/types/chapters.js +0 -0
- package/dist/src/types/index.d.ts +2 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +2 -0
- package/dist/src/types/metadata-mappings.d.ts +1 -1
- package/dist/src/types/metadata-mappings.d.ts.map +1 -1
- package/dist/src/types/tags.d.ts +11 -7
- package/dist/src/types/tags.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/wasm.d.ts +14 -2
- package/dist/src/wasm.d.ts.map +1 -1
- package/dist/taglib-wasi.wasm +0 -0
- package/dist/taglib-web.wasm +0 -0
- package/dist/taglib-wrapper.d.ts +0 -2
- package/dist/taglib-wrapper.js +1 -1
- package/package.json +5 -5
- package/dist/taglib_wasi.wasm +0 -0
package/dist/simple.browser.js
CHANGED
|
@@ -88,6 +88,20 @@ var init_pictures = __esm({
|
|
|
88
88
|
}
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
+
// src/types/chapters.ts
|
|
92
|
+
var init_chapters = __esm({
|
|
93
|
+
"src/types/chapters.ts"() {
|
|
94
|
+
"use strict";
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// src/types/bwf.ts
|
|
99
|
+
var init_bwf = __esm({
|
|
100
|
+
"src/types/bwf.ts"() {
|
|
101
|
+
"use strict";
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
91
105
|
// src/types/config.ts
|
|
92
106
|
var init_config = __esm({
|
|
93
107
|
"src/types/config.ts"() {
|
|
@@ -110,6 +124,8 @@ var init_types = __esm({
|
|
|
110
124
|
init_tags();
|
|
111
125
|
init_metadata_mappings();
|
|
112
126
|
init_pictures();
|
|
127
|
+
init_chapters();
|
|
128
|
+
init_bwf();
|
|
113
129
|
init_config();
|
|
114
130
|
init_format_property_keys();
|
|
115
131
|
}
|
|
@@ -123,6 +139,136 @@ var init_types2 = __esm({
|
|
|
123
139
|
}
|
|
124
140
|
});
|
|
125
141
|
|
|
142
|
+
// src/bwf/bext.ts
|
|
143
|
+
function readFixedString(bytes, offset, len) {
|
|
144
|
+
let end = offset;
|
|
145
|
+
const max = Math.min(offset + len, bytes.length);
|
|
146
|
+
while (end < max && bytes[end] !== 0) end++;
|
|
147
|
+
let s = "";
|
|
148
|
+
for (let i = offset; i < end; i++) s += String.fromCharCode(bytes[i]);
|
|
149
|
+
return s;
|
|
150
|
+
}
|
|
151
|
+
function writeFixedString(bytes, offset, len, value) {
|
|
152
|
+
for (let i = 0; i < len; i++) {
|
|
153
|
+
bytes[offset + i] = i < value.length ? value.charCodeAt(i) & 255 : 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function clampInt16(n) {
|
|
157
|
+
return Math.max(-32768, Math.min(32767, Math.round(n)));
|
|
158
|
+
}
|
|
159
|
+
function loudnessRaw(v) {
|
|
160
|
+
return v === void 0 ? LOUDNESS_UNSET : clampInt16(v * 100);
|
|
161
|
+
}
|
|
162
|
+
function loudnessFromRaw(raw) {
|
|
163
|
+
return raw === LOUDNESS_UNSET ? void 0 : raw / 100;
|
|
164
|
+
}
|
|
165
|
+
function bytesToHex(bytes) {
|
|
166
|
+
let s = "";
|
|
167
|
+
for (const b of bytes) s += b.toString(16).padStart(2, "0");
|
|
168
|
+
return s;
|
|
169
|
+
}
|
|
170
|
+
function hexToBytes(hex, outLen) {
|
|
171
|
+
const clean = hex.replace(/[^0-9a-fA-F]/g, "");
|
|
172
|
+
const out = new Uint8Array(outLen);
|
|
173
|
+
for (let i = 0; i + 1 < clean.length + 1 && i / 2 < outLen; i += 2) {
|
|
174
|
+
const pair = clean.slice(i, i + 2);
|
|
175
|
+
if (pair.length === 2) out[i / 2] = parseInt(pair, 16);
|
|
176
|
+
}
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
179
|
+
function decodeBext(bytes) {
|
|
180
|
+
if (bytes.length < VERSION_OFFSET + 2) return void 0;
|
|
181
|
+
const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
182
|
+
const timeRefLow = dv.getUint32(338, true);
|
|
183
|
+
const timeRefHigh = dv.getUint32(342, true);
|
|
184
|
+
const version = dv.getUint16(VERSION_OFFSET, true);
|
|
185
|
+
const result = {
|
|
186
|
+
description: readFixedString(bytes, 0, 256),
|
|
187
|
+
originator: readFixedString(bytes, 256, 32),
|
|
188
|
+
originatorReference: readFixedString(bytes, 288, 32),
|
|
189
|
+
originationDate: readFixedString(bytes, 320, 10),
|
|
190
|
+
originationTime: readFixedString(bytes, 330, 8),
|
|
191
|
+
timeReferenceSamples: BigInt(timeRefHigh) << 32n | BigInt(timeRefLow),
|
|
192
|
+
version,
|
|
193
|
+
codingHistory: bytes.length > FIXED_PREFIX_LEN ? readFixedString(
|
|
194
|
+
bytes,
|
|
195
|
+
FIXED_PREFIX_LEN,
|
|
196
|
+
bytes.length - FIXED_PREFIX_LEN
|
|
197
|
+
) : ""
|
|
198
|
+
};
|
|
199
|
+
if (version >= 1 && bytes.length >= UMID_OFFSET + UMID_LEN) {
|
|
200
|
+
result.umid = bytesToHex(
|
|
201
|
+
bytes.subarray(UMID_OFFSET, UMID_OFFSET + UMID_LEN)
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
if (version >= 2 && bytes.length >= LOUDNESS_OFFSET + 10) {
|
|
205
|
+
const lv = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET, true));
|
|
206
|
+
const lr = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET + 2, true));
|
|
207
|
+
const mtp = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET + 4, true));
|
|
208
|
+
const mml = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET + 6, true));
|
|
209
|
+
const msl = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET + 8, true));
|
|
210
|
+
if (lv !== void 0) result.loudnessValueDb = lv;
|
|
211
|
+
if (lr !== void 0) result.loudnessRangeDb = lr;
|
|
212
|
+
if (mtp !== void 0) result.maxTruePeakLevelDbtp = mtp;
|
|
213
|
+
if (mml !== void 0) result.maxMomentaryLoudnessDb = mml;
|
|
214
|
+
if (msl !== void 0) result.maxShortTermLoudnessDb = msl;
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
function encodeBext(b) {
|
|
219
|
+
const codingHistory = b.codingHistory ?? "";
|
|
220
|
+
const bytes = new Uint8Array(FIXED_PREFIX_LEN + codingHistory.length);
|
|
221
|
+
const dv = new DataView(bytes.buffer);
|
|
222
|
+
const hasLoudness = b.loudnessValueDb !== void 0 || b.loudnessRangeDb !== void 0 || b.maxTruePeakLevelDbtp !== void 0 || b.maxMomentaryLoudnessDb !== void 0 || b.maxShortTermLoudnessDb !== void 0;
|
|
223
|
+
const version = Number.isInteger(b.version) ? b.version : hasLoudness ? 2 : b.umid ? 1 : 0;
|
|
224
|
+
writeFixedString(bytes, 0, 256, b.description ?? "");
|
|
225
|
+
writeFixedString(bytes, 256, 32, b.originator ?? "");
|
|
226
|
+
writeFixedString(bytes, 288, 32, b.originatorReference ?? "");
|
|
227
|
+
writeFixedString(bytes, 320, 10, b.originationDate ?? "");
|
|
228
|
+
writeFixedString(bytes, 330, 8, b.originationTime ?? "");
|
|
229
|
+
const tr = b.timeReferenceSamples ?? 0n;
|
|
230
|
+
dv.setUint32(338, Number(tr & 0xffffffffn), true);
|
|
231
|
+
dv.setUint32(342, Number(tr >> 32n & 0xffffffffn), true);
|
|
232
|
+
dv.setUint16(VERSION_OFFSET, version, true);
|
|
233
|
+
if (version >= 1 && b.umid) {
|
|
234
|
+
bytes.set(hexToBytes(b.umid, UMID_LEN), UMID_OFFSET);
|
|
235
|
+
}
|
|
236
|
+
if (version >= 2) {
|
|
237
|
+
dv.setInt16(LOUDNESS_OFFSET, loudnessRaw(b.loudnessValueDb), true);
|
|
238
|
+
dv.setInt16(LOUDNESS_OFFSET + 2, loudnessRaw(b.loudnessRangeDb), true);
|
|
239
|
+
dv.setInt16(LOUDNESS_OFFSET + 4, loudnessRaw(b.maxTruePeakLevelDbtp), true);
|
|
240
|
+
dv.setInt16(
|
|
241
|
+
LOUDNESS_OFFSET + 6,
|
|
242
|
+
loudnessRaw(b.maxMomentaryLoudnessDb),
|
|
243
|
+
true
|
|
244
|
+
);
|
|
245
|
+
dv.setInt16(
|
|
246
|
+
LOUDNESS_OFFSET + 8,
|
|
247
|
+
loudnessRaw(b.maxShortTermLoudnessDb),
|
|
248
|
+
true
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
writeFixedString(
|
|
252
|
+
bytes,
|
|
253
|
+
FIXED_PREFIX_LEN,
|
|
254
|
+
codingHistory.length,
|
|
255
|
+
codingHistory
|
|
256
|
+
);
|
|
257
|
+
return bytes;
|
|
258
|
+
}
|
|
259
|
+
var FIXED_PREFIX_LEN, VERSION_OFFSET, UMID_OFFSET, UMID_LEN, LOUDNESS_OFFSET, LOUDNESS_UNSET;
|
|
260
|
+
var init_bext = __esm({
|
|
261
|
+
"src/bwf/bext.ts"() {
|
|
262
|
+
"use strict";
|
|
263
|
+
FIXED_PREFIX_LEN = 602;
|
|
264
|
+
VERSION_OFFSET = 346;
|
|
265
|
+
UMID_OFFSET = 348;
|
|
266
|
+
UMID_LEN = 64;
|
|
267
|
+
LOUDNESS_OFFSET = 412;
|
|
268
|
+
LOUDNESS_UNSET = 32767;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
126
272
|
// src/errors/base.ts
|
|
127
273
|
var SUPPORTED_FORMATS, TagLibError;
|
|
128
274
|
var init_base = __esm({
|
|
@@ -365,6 +511,47 @@ var init_errors2 = __esm({
|
|
|
365
511
|
}
|
|
366
512
|
});
|
|
367
513
|
|
|
514
|
+
// src/taglib/audio-file-bwf.ts
|
|
515
|
+
function requireBwf(format) {
|
|
516
|
+
if (!BWF_FORMATS.has(format)) {
|
|
517
|
+
throw new UnsupportedFormatError(format, ["WAV", "FLAC"], {
|
|
518
|
+
operation: "BWF metadata"
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function getBextData(handle) {
|
|
523
|
+
const raw = handle.getBextData();
|
|
524
|
+
return raw && raw.length > 0 ? raw : void 0;
|
|
525
|
+
}
|
|
526
|
+
function setBextData(handle, format, data) {
|
|
527
|
+
requireBwf(format);
|
|
528
|
+
handle.setBextData(data);
|
|
529
|
+
}
|
|
530
|
+
function getBext(handle) {
|
|
531
|
+
const raw = handle.getBextData();
|
|
532
|
+
return raw && raw.length > 0 ? decodeBext(raw) : void 0;
|
|
533
|
+
}
|
|
534
|
+
function setBext(handle, format, bext) {
|
|
535
|
+
requireBwf(format);
|
|
536
|
+
handle.setBextData(encodeBext(bext));
|
|
537
|
+
}
|
|
538
|
+
function getIxml(handle) {
|
|
539
|
+
return handle.getIxml();
|
|
540
|
+
}
|
|
541
|
+
function setIxml(handle, format, data) {
|
|
542
|
+
requireBwf(format);
|
|
543
|
+
handle.setIxml(data);
|
|
544
|
+
}
|
|
545
|
+
var BWF_FORMATS;
|
|
546
|
+
var init_audio_file_bwf = __esm({
|
|
547
|
+
"src/taglib/audio-file-bwf.ts"() {
|
|
548
|
+
"use strict";
|
|
549
|
+
init_bext();
|
|
550
|
+
init_errors2();
|
|
551
|
+
BWF_FORMATS = /* @__PURE__ */ new Set(["WAV", "FLAC"]);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
|
|
368
555
|
// browser-stub:platform-io-browser-stub
|
|
369
556
|
function getPlatformIO() {
|
|
370
557
|
throw new Error("Filesystem operations are not available in the browser.");
|
|
@@ -1347,6 +1534,9 @@ var init_audio_file_base = __esm({
|
|
|
1347
1534
|
});
|
|
1348
1535
|
|
|
1349
1536
|
// src/taglib/embind-adapter.ts
|
|
1537
|
+
function isValidBitrateMode(value) {
|
|
1538
|
+
return value === "CBR" || value === "VBR" || value === "ABR";
|
|
1539
|
+
}
|
|
1350
1540
|
function wrapEmbindHandle(raw) {
|
|
1351
1541
|
const overrides = {
|
|
1352
1542
|
getTagData() {
|
|
@@ -1371,12 +1561,32 @@ function wrapEmbindHandle(raw) {
|
|
|
1371
1561
|
if (data.year !== void 0) tw.setYear(data.year);
|
|
1372
1562
|
if (data.track !== void 0) tw.setTrack(data.track);
|
|
1373
1563
|
},
|
|
1564
|
+
getBextData() {
|
|
1565
|
+
const v = raw.getBextData();
|
|
1566
|
+
if (v === void 0 || v === null) return void 0;
|
|
1567
|
+
const u8 = v instanceof Uint8Array ? v : new Uint8Array(v);
|
|
1568
|
+
return u8.length > 0 ? u8 : void 0;
|
|
1569
|
+
},
|
|
1570
|
+
setBextData(data) {
|
|
1571
|
+
raw.setBextData(data ?? null);
|
|
1572
|
+
},
|
|
1573
|
+
getIxml() {
|
|
1574
|
+
const v = raw.getIxml();
|
|
1575
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
1576
|
+
},
|
|
1577
|
+
setIxml(data) {
|
|
1578
|
+
raw.setIxml(
|
|
1579
|
+
data ?? null
|
|
1580
|
+
);
|
|
1581
|
+
},
|
|
1374
1582
|
getAudioProperties() {
|
|
1375
1583
|
const pw = raw.getAudioProperties();
|
|
1376
1584
|
if (!pw) return null;
|
|
1377
1585
|
const containerFormat = pw.containerFormat() || "unknown";
|
|
1586
|
+
const codec = pw.codec() || "unknown";
|
|
1378
1587
|
const mpegVersion = pw.mpegVersion();
|
|
1379
1588
|
const formatVersion = pw.formatVersion();
|
|
1589
|
+
const bitrateMode = pw.bitrateMode();
|
|
1380
1590
|
return {
|
|
1381
1591
|
duration: pw.lengthInSeconds(),
|
|
1382
1592
|
durationMs: pw.lengthInMilliseconds(),
|
|
@@ -1384,12 +1594,14 @@ function wrapEmbindHandle(raw) {
|
|
|
1384
1594
|
sampleRate: pw.sampleRate(),
|
|
1385
1595
|
channels: pw.channels(),
|
|
1386
1596
|
bitsPerSample: pw.bitsPerSample(),
|
|
1387
|
-
codec
|
|
1597
|
+
codec,
|
|
1388
1598
|
containerFormat,
|
|
1389
1599
|
isLossless: pw.isLossless(),
|
|
1390
1600
|
...mpegVersion > 0 ? { mpegVersion, mpegLayer: pw.mpegLayer() } : {},
|
|
1391
1601
|
...containerFormat === "MP4" || containerFormat === "ASF" ? { isEncrypted: pw.isEncrypted() } : {},
|
|
1392
|
-
...formatVersion > 0 ? { formatVersion } : {}
|
|
1602
|
+
...formatVersion > 0 ? { formatVersion } : {},
|
|
1603
|
+
...isValidBitrateMode(bitrateMode) ? { bitrateMode } : {},
|
|
1604
|
+
...codec === "Opus" ? { outputGainDb: pw.outputGainDb() } : {}
|
|
1393
1605
|
};
|
|
1394
1606
|
}
|
|
1395
1607
|
};
|
|
@@ -1408,6 +1620,15 @@ var init_embind_adapter = __esm({
|
|
|
1408
1620
|
});
|
|
1409
1621
|
|
|
1410
1622
|
// src/taglib/audio-file-impl.ts
|
|
1623
|
+
function sortChapters(list) {
|
|
1624
|
+
return [...list].sort((a, b) => a.startTimeMs - b.startTimeMs);
|
|
1625
|
+
}
|
|
1626
|
+
function inferEndTimeMs(sorted, index, trackEndMs) {
|
|
1627
|
+
const own = sorted[index].endTimeMs;
|
|
1628
|
+
if (own !== void 0) return own;
|
|
1629
|
+
const next = sorted[index + 1];
|
|
1630
|
+
return next ? next.startTimeMs : trackEndMs;
|
|
1631
|
+
}
|
|
1411
1632
|
function readFileSync(path) {
|
|
1412
1633
|
if (typeof Deno !== "undefined") return Deno.readFileSync(path);
|
|
1413
1634
|
if (_nodeFs === void 0) {
|
|
@@ -1425,6 +1646,7 @@ var init_audio_file_impl = __esm({
|
|
|
1425
1646
|
"src/taglib/audio-file-impl.ts"() {
|
|
1426
1647
|
"use strict";
|
|
1427
1648
|
init_types2();
|
|
1649
|
+
init_audio_file_bwf();
|
|
1428
1650
|
init_errors2();
|
|
1429
1651
|
init_file();
|
|
1430
1652
|
init_write();
|
|
@@ -1490,6 +1712,10 @@ var init_audio_file_impl = __esm({
|
|
|
1490
1712
|
fullFileHandle.setTagData(this.handle.getTagData());
|
|
1491
1713
|
fullFileHandle.setProperties(this.handle.getProperties());
|
|
1492
1714
|
fullFileHandle.setPictures(this.handle.getPictures());
|
|
1715
|
+
const bextBytes = this.handle.getBextData();
|
|
1716
|
+
if (bextBytes !== void 0) fullFileHandle.setBextData(bextBytes);
|
|
1717
|
+
const ixmlStr = this.handle.getIxml();
|
|
1718
|
+
if (ixmlStr !== void 0) fullFileHandle.setIxml(ixmlStr);
|
|
1493
1719
|
if (!fullFileHandle.save()) {
|
|
1494
1720
|
throw new FileOperationError(
|
|
1495
1721
|
"save",
|
|
@@ -1544,6 +1770,52 @@ var init_audio_file_impl = __esm({
|
|
|
1544
1770
|
removePictures() {
|
|
1545
1771
|
this.handle.removePictures();
|
|
1546
1772
|
}
|
|
1773
|
+
getChapters() {
|
|
1774
|
+
const sorted = sortChapters(this.handle.getChapters());
|
|
1775
|
+
const trackEndMs = this.audioProperties()?.durationMs;
|
|
1776
|
+
return sorted.map((c, i) => ({
|
|
1777
|
+
startTimeMs: c.startTimeMs,
|
|
1778
|
+
endTimeMs: inferEndTimeMs(sorted, i, trackEndMs),
|
|
1779
|
+
title: c.title || void 0,
|
|
1780
|
+
id: c.id || void 0,
|
|
1781
|
+
source: c.source
|
|
1782
|
+
}));
|
|
1783
|
+
}
|
|
1784
|
+
setChapters(chapters, options) {
|
|
1785
|
+
const fmt = this.getFormat();
|
|
1786
|
+
if (fmt !== "MP3" && fmt !== "MP4") {
|
|
1787
|
+
throw new UnsupportedFormatError(fmt, ["MP3", "MP4"], {
|
|
1788
|
+
operation: "setChapters"
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
const sorted = sortChapters(chapters);
|
|
1792
|
+
const trackEndMs = this.audioProperties()?.durationMs;
|
|
1793
|
+
const raw = sorted.map((c, i) => ({
|
|
1794
|
+
id: c.id,
|
|
1795
|
+
startTimeMs: c.startTimeMs,
|
|
1796
|
+
endTimeMs: inferEndTimeMs(sorted, i, trackEndMs) ?? c.startTimeMs,
|
|
1797
|
+
title: c.title
|
|
1798
|
+
}));
|
|
1799
|
+
this.handle.setChapters(raw, options?.mp4ChapterStyle ?? "quicktime");
|
|
1800
|
+
}
|
|
1801
|
+
getBext() {
|
|
1802
|
+
return getBext(this.handle);
|
|
1803
|
+
}
|
|
1804
|
+
setBext(bext) {
|
|
1805
|
+
setBext(this.handle, this.getFormat(), bext);
|
|
1806
|
+
}
|
|
1807
|
+
getBextData() {
|
|
1808
|
+
return getBextData(this.handle);
|
|
1809
|
+
}
|
|
1810
|
+
setBextData(data) {
|
|
1811
|
+
setBextData(this.handle, this.getFormat(), data);
|
|
1812
|
+
}
|
|
1813
|
+
getIxml() {
|
|
1814
|
+
return getIxml(this.handle);
|
|
1815
|
+
}
|
|
1816
|
+
setIxml(data) {
|
|
1817
|
+
setIxml(this.handle, this.getFormat(), data);
|
|
1818
|
+
}
|
|
1547
1819
|
getRatings() {
|
|
1548
1820
|
return this.handle.getRatings().map(
|
|
1549
1821
|
(r) => ({
|
|
@@ -1717,7 +1989,7 @@ var VERSION;
|
|
|
1717
1989
|
var init_version = __esm({
|
|
1718
1990
|
"src/version.ts"() {
|
|
1719
1991
|
"use strict";
|
|
1720
|
-
VERSION = "1.
|
|
1992
|
+
VERSION = "1.2.0";
|
|
1721
1993
|
}
|
|
1722
1994
|
});
|
|
1723
1995
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview EBU Tech 3285 BWF `bext` chunk codec. Pure functions — no Wasm
|
|
3
|
+
* or TagLib dependency. The fixed prefix is 602 bytes for all versions; the
|
|
4
|
+
* `version` field selects which optional fields are meaningful (0 = none,
|
|
5
|
+
* 1 = UMID, 2 = UMID + loudness). Fixed-width string fields are NUL-padded
|
|
6
|
+
* ASCII; `codingHistory` is exposed verbatim (the spec uses CR/LF lines) and
|
|
7
|
+
* is not promised to preserve embedded NUL bytes. Loudness fields use the EBU
|
|
8
|
+
* "value not set" sentinel `0x7FFF`: a sentinel decodes to `undefined`, and an
|
|
9
|
+
* `undefined` loudness field on a v2 encode is written as the sentinel.
|
|
10
|
+
*/
|
|
11
|
+
import type { BroadcastAudioExtension } from "../types/bwf.js";
|
|
12
|
+
/**
|
|
13
|
+
* Parse a raw `bext` chunk. Returns `undefined` only if `bytes` is shorter than
|
|
14
|
+
* 348 (cannot even read the `Version` field). Optional fields are populated per
|
|
15
|
+
* the chunk's declared version and the available length, so compact/legacy v0
|
|
16
|
+
* chunks parse into a partial struct.
|
|
17
|
+
*/
|
|
18
|
+
export declare function decodeBext(bytes: Uint8Array): BroadcastAudioExtension | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Serialize a `bext` chunk. The result is always `602 + codingHistory.length`
|
|
21
|
+
* bytes. `version` defaults to 2 when any loudness field is present (else 1 if
|
|
22
|
+
* `umid` is set, else 0). Over-long string fields are truncated to their widths;
|
|
23
|
+
* loudness values are clamped to the Int16 range after ×100, with `undefined`
|
|
24
|
+
* written as the EBU `0x7FFF` "not set" sentinel; UMID is written only for
|
|
25
|
+
* version ≥ 1.
|
|
26
|
+
*/
|
|
27
|
+
export declare function encodeBext(b: BroadcastAudioExtension): Uint8Array;
|
|
28
|
+
//# sourceMappingURL=bext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bext.d.ts","sourceRoot":"","sources":["../../../src/bwf/bext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AA6D/D;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,UAAU,GAChB,uBAAuB,GAAG,SAAS,CAwCrC;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,uBAAuB,GAAG,UAAU,CA6CjE"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const FIXED_PREFIX_LEN = 602;
|
|
2
|
+
const VERSION_OFFSET = 346;
|
|
3
|
+
const UMID_OFFSET = 348;
|
|
4
|
+
const UMID_LEN = 64;
|
|
5
|
+
const LOUDNESS_OFFSET = 412;
|
|
6
|
+
const LOUDNESS_UNSET = 32767;
|
|
7
|
+
function readFixedString(bytes, offset, len) {
|
|
8
|
+
let end = offset;
|
|
9
|
+
const max = Math.min(offset + len, bytes.length);
|
|
10
|
+
while (end < max && bytes[end] !== 0) end++;
|
|
11
|
+
let s = "";
|
|
12
|
+
for (let i = offset; i < end; i++) s += String.fromCharCode(bytes[i]);
|
|
13
|
+
return s;
|
|
14
|
+
}
|
|
15
|
+
function writeFixedString(bytes, offset, len, value) {
|
|
16
|
+
for (let i = 0; i < len; i++) {
|
|
17
|
+
bytes[offset + i] = i < value.length ? value.charCodeAt(i) & 255 : 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function clampInt16(n) {
|
|
21
|
+
return Math.max(-32768, Math.min(32767, Math.round(n)));
|
|
22
|
+
}
|
|
23
|
+
function loudnessRaw(v) {
|
|
24
|
+
return v === void 0 ? LOUDNESS_UNSET : clampInt16(v * 100);
|
|
25
|
+
}
|
|
26
|
+
function loudnessFromRaw(raw) {
|
|
27
|
+
return raw === LOUDNESS_UNSET ? void 0 : raw / 100;
|
|
28
|
+
}
|
|
29
|
+
function bytesToHex(bytes) {
|
|
30
|
+
let s = "";
|
|
31
|
+
for (const b of bytes) s += b.toString(16).padStart(2, "0");
|
|
32
|
+
return s;
|
|
33
|
+
}
|
|
34
|
+
function hexToBytes(hex, outLen) {
|
|
35
|
+
const clean = hex.replace(/[^0-9a-fA-F]/g, "");
|
|
36
|
+
const out = new Uint8Array(outLen);
|
|
37
|
+
for (let i = 0; i + 1 < clean.length + 1 && i / 2 < outLen; i += 2) {
|
|
38
|
+
const pair = clean.slice(i, i + 2);
|
|
39
|
+
if (pair.length === 2) out[i / 2] = parseInt(pair, 16);
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
function decodeBext(bytes) {
|
|
44
|
+
if (bytes.length < VERSION_OFFSET + 2) return void 0;
|
|
45
|
+
const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
46
|
+
const timeRefLow = dv.getUint32(338, true);
|
|
47
|
+
const timeRefHigh = dv.getUint32(342, true);
|
|
48
|
+
const version = dv.getUint16(VERSION_OFFSET, true);
|
|
49
|
+
const result = {
|
|
50
|
+
description: readFixedString(bytes, 0, 256),
|
|
51
|
+
originator: readFixedString(bytes, 256, 32),
|
|
52
|
+
originatorReference: readFixedString(bytes, 288, 32),
|
|
53
|
+
originationDate: readFixedString(bytes, 320, 10),
|
|
54
|
+
originationTime: readFixedString(bytes, 330, 8),
|
|
55
|
+
timeReferenceSamples: BigInt(timeRefHigh) << 32n | BigInt(timeRefLow),
|
|
56
|
+
version,
|
|
57
|
+
codingHistory: bytes.length > FIXED_PREFIX_LEN ? readFixedString(
|
|
58
|
+
bytes,
|
|
59
|
+
FIXED_PREFIX_LEN,
|
|
60
|
+
bytes.length - FIXED_PREFIX_LEN
|
|
61
|
+
) : ""
|
|
62
|
+
};
|
|
63
|
+
if (version >= 1 && bytes.length >= UMID_OFFSET + UMID_LEN) {
|
|
64
|
+
result.umid = bytesToHex(
|
|
65
|
+
bytes.subarray(UMID_OFFSET, UMID_OFFSET + UMID_LEN)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
if (version >= 2 && bytes.length >= LOUDNESS_OFFSET + 10) {
|
|
69
|
+
const lv = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET, true));
|
|
70
|
+
const lr = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET + 2, true));
|
|
71
|
+
const mtp = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET + 4, true));
|
|
72
|
+
const mml = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET + 6, true));
|
|
73
|
+
const msl = loudnessFromRaw(dv.getInt16(LOUDNESS_OFFSET + 8, true));
|
|
74
|
+
if (lv !== void 0) result.loudnessValueDb = lv;
|
|
75
|
+
if (lr !== void 0) result.loudnessRangeDb = lr;
|
|
76
|
+
if (mtp !== void 0) result.maxTruePeakLevelDbtp = mtp;
|
|
77
|
+
if (mml !== void 0) result.maxMomentaryLoudnessDb = mml;
|
|
78
|
+
if (msl !== void 0) result.maxShortTermLoudnessDb = msl;
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
function encodeBext(b) {
|
|
83
|
+
const codingHistory = b.codingHistory ?? "";
|
|
84
|
+
const bytes = new Uint8Array(FIXED_PREFIX_LEN + codingHistory.length);
|
|
85
|
+
const dv = new DataView(bytes.buffer);
|
|
86
|
+
const hasLoudness = b.loudnessValueDb !== void 0 || b.loudnessRangeDb !== void 0 || b.maxTruePeakLevelDbtp !== void 0 || b.maxMomentaryLoudnessDb !== void 0 || b.maxShortTermLoudnessDb !== void 0;
|
|
87
|
+
const version = Number.isInteger(b.version) ? b.version : hasLoudness ? 2 : b.umid ? 1 : 0;
|
|
88
|
+
writeFixedString(bytes, 0, 256, b.description ?? "");
|
|
89
|
+
writeFixedString(bytes, 256, 32, b.originator ?? "");
|
|
90
|
+
writeFixedString(bytes, 288, 32, b.originatorReference ?? "");
|
|
91
|
+
writeFixedString(bytes, 320, 10, b.originationDate ?? "");
|
|
92
|
+
writeFixedString(bytes, 330, 8, b.originationTime ?? "");
|
|
93
|
+
const tr = b.timeReferenceSamples ?? 0n;
|
|
94
|
+
dv.setUint32(338, Number(tr & 0xffffffffn), true);
|
|
95
|
+
dv.setUint32(342, Number(tr >> 32n & 0xffffffffn), true);
|
|
96
|
+
dv.setUint16(VERSION_OFFSET, version, true);
|
|
97
|
+
if (version >= 1 && b.umid) {
|
|
98
|
+
bytes.set(hexToBytes(b.umid, UMID_LEN), UMID_OFFSET);
|
|
99
|
+
}
|
|
100
|
+
if (version >= 2) {
|
|
101
|
+
dv.setInt16(LOUDNESS_OFFSET, loudnessRaw(b.loudnessValueDb), true);
|
|
102
|
+
dv.setInt16(LOUDNESS_OFFSET + 2, loudnessRaw(b.loudnessRangeDb), true);
|
|
103
|
+
dv.setInt16(LOUDNESS_OFFSET + 4, loudnessRaw(b.maxTruePeakLevelDbtp), true);
|
|
104
|
+
dv.setInt16(
|
|
105
|
+
LOUDNESS_OFFSET + 6,
|
|
106
|
+
loudnessRaw(b.maxMomentaryLoudnessDb),
|
|
107
|
+
true
|
|
108
|
+
);
|
|
109
|
+
dv.setInt16(
|
|
110
|
+
LOUDNESS_OFFSET + 8,
|
|
111
|
+
loudnessRaw(b.maxShortTermLoudnessDb),
|
|
112
|
+
true
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
writeFixedString(
|
|
116
|
+
bytes,
|
|
117
|
+
FIXED_PREFIX_LEN,
|
|
118
|
+
codingHistory.length,
|
|
119
|
+
codingHistory
|
|
120
|
+
);
|
|
121
|
+
return bytes;
|
|
122
|
+
}
|
|
123
|
+
export {
|
|
124
|
+
decodeBext,
|
|
125
|
+
encodeBext
|
|
126
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/msgpack/encoder.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAE/D,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACZ,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/msgpack/encoder.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAE/D,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACZ,MAAM,aAAa,CAAC;AAsBrB,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAiB9D;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,eAAe,GAAG,UAAU,CAS7E;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAStE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAe1D;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,UAAU,CAelE;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,IAAI,EAAE,CAAC,EACP,OAAO,GAAE,OAAO,CAAC,cAAc,CAAM,GACpC,UAAU,CAUZ;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,UAAU,CAe/D;AAqBD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,UAAU,CAc1E;AAED,wBAAiB,uBAAuB,CAAC,CAAC,EACxC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,GACxB,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CActC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAS7D;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,GAC1E,UAAU,CAeZ;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAW7D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG;IACxD,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAaA"}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { encode } from "@msgpack/msgpack";
|
|
2
2
|
import { errorMessage, MetadataError } from "../errors/classes.js";
|
|
3
3
|
import { toTagLibKey } from "../constants/properties.js";
|
|
4
|
-
const PASSTHROUGH_KEYS = /* @__PURE__ */ new Set([
|
|
4
|
+
const PASSTHROUGH_KEYS = /* @__PURE__ */ new Set([
|
|
5
|
+
"pictures",
|
|
6
|
+
"ratings",
|
|
7
|
+
"lyrics",
|
|
8
|
+
"chapters",
|
|
9
|
+
"_mp4ChapterStyle",
|
|
10
|
+
"bextData",
|
|
11
|
+
"ixml"
|
|
12
|
+
]);
|
|
5
13
|
const MSGPACK_ENCODE_OPTIONS = {
|
|
6
14
|
sortKeys: false,
|
|
7
15
|
forceFloat32: false,
|
|
@@ -38,7 +38,7 @@ async function loadModule(wasmType, runtime, options) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
async function loadWasiModuleWithFallback(runtime, options) {
|
|
41
|
-
const defaultWasmPath = resolveWasmPath("../../../
|
|
41
|
+
const defaultWasmPath = resolveWasmPath("../../../taglib-wasi.wasm");
|
|
42
42
|
try {
|
|
43
43
|
const { loadWasiHost } = await import("../wasi-host-loader.js");
|
|
44
44
|
const wasiModule = await loadWasiHost({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview WASI-based FileHandle implementation
|
|
3
3
|
*/
|
|
4
|
-
import type { FileHandle, RawPicture } from "../../wasm.js";
|
|
4
|
+
import type { FileHandle, RawChapter, RawPicture } from "../../wasm.js";
|
|
5
5
|
import type { BasicTagData } from "../../types/tags.js";
|
|
6
6
|
import type { AudioProperties } from "../../types.js";
|
|
7
7
|
import type { WasiModule } from "../wasmer-sdk-loader/types.js";
|
|
@@ -35,6 +35,12 @@ export declare class WasiFileHandle implements FileHandle {
|
|
|
35
35
|
setPictures(pictures: RawPicture[]): void;
|
|
36
36
|
addPicture(picture: RawPicture): void;
|
|
37
37
|
removePictures(): void;
|
|
38
|
+
getChapters(): RawChapter[];
|
|
39
|
+
setChapters(chapters: RawChapter[], mp4ChapterStyle: string): void;
|
|
40
|
+
getBextData(): Uint8Array | undefined;
|
|
41
|
+
setBextData(data: Uint8Array | null): void;
|
|
42
|
+
getIxml(): string | undefined;
|
|
43
|
+
setIxml(data: string | null): void;
|
|
38
44
|
getRatings(): {
|
|
39
45
|
rating: number;
|
|
40
46
|
email: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-handle.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/file-handle.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"file-handle.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/file-handle.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AA8DhE,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAAwC;IACvD,OAAO,CAAC,SAAS,CAAS;gBAEd,UAAU,EAAE,UAAU;IAIlC,OAAO,CAAC,iBAAiB;IAQzB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO;IAW3C,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAWnC,OAAO,IAAI,OAAO;IAMlB,IAAI,IAAI,OAAO;IAqBf,UAAU,IAAI,YAAY;IAc1B,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAK7C,kBAAkB,IAAI,eAAe,GAAG,IAAI;IA+B5C,SAAS,IAAI,MAAM;IA2DnB,OAAO,CAAC,cAAc;IAiBtB,SAAS,IAAI,UAAU;IAKvB,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAuBzC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI;IAgBpD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAOhC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAc7C,KAAK,IAAI,OAAO;IAehB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAK/B,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK5C,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAShC,WAAW,IAAI,UAAU,EAAE;IAK3B,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI;IAKzC,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAOrC,cAAc,IAAI,IAAI;IAKtB,WAAW,IAAI,UAAU,EAAE;IAK3B,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI;IASlE,WAAW,IAAI,UAAU,GAAG,SAAS;IAKrC,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAS1C,OAAO,IAAI,MAAM,GAAG,SAAS;IAM7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAKlC,UAAU,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE;IAOlE,UAAU,CACR,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GAC9D,IAAI;IAaP,OAAO,IAAI,IAAI;CAKhB"}
|
|
@@ -24,9 +24,18 @@ const AUDIO_KEYS = /* @__PURE__ */ new Set([
|
|
|
24
24
|
"lengthMs",
|
|
25
25
|
"mpegLayer",
|
|
26
26
|
"mpegVersion",
|
|
27
|
+
"outputGainDb",
|
|
27
28
|
"sampleRate"
|
|
28
29
|
]);
|
|
29
|
-
const INTERNAL_KEYS = /* @__PURE__ */ new Set([
|
|
30
|
+
const INTERNAL_KEYS = /* @__PURE__ */ new Set([
|
|
31
|
+
"pictures",
|
|
32
|
+
"ratings",
|
|
33
|
+
"lyrics",
|
|
34
|
+
"chapters",
|
|
35
|
+
"_mp4ChapterStyle",
|
|
36
|
+
"bextData",
|
|
37
|
+
"ixml"
|
|
38
|
+
]);
|
|
30
39
|
const CONTAINER_TO_FORMAT = {
|
|
31
40
|
MP3: "MP3",
|
|
32
41
|
MP4: "MP4",
|
|
@@ -135,7 +144,8 @@ class WasiFileHandle {
|
|
|
135
144
|
isLossless: d.isLossless ?? false,
|
|
136
145
|
...mpegVersion > 0 ? { mpegVersion, mpegLayer: d.mpegLayer ?? 0 } : {},
|
|
137
146
|
...containerFormat === "MP4" || containerFormat === "ASF" ? { isEncrypted: d.isEncrypted ?? false } : {},
|
|
138
|
-
...formatVersion > 0 ? { formatVersion } : {}
|
|
147
|
+
...formatVersion > 0 ? { formatVersion } : {},
|
|
148
|
+
...d.outputGainDb !== void 0 ? { outputGainDb: d.outputGainDb } : {}
|
|
139
149
|
};
|
|
140
150
|
}
|
|
141
151
|
getFormat() {
|
|
@@ -275,6 +285,35 @@ class WasiFileHandle {
|
|
|
275
285
|
this.checkNotDestroyed();
|
|
276
286
|
this.tagData = { ...this.tagData, pictures: [] };
|
|
277
287
|
}
|
|
288
|
+
getChapters() {
|
|
289
|
+
this.checkNotDestroyed();
|
|
290
|
+
return this.tagData?.chapters ?? [];
|
|
291
|
+
}
|
|
292
|
+
setChapters(chapters, mp4ChapterStyle) {
|
|
293
|
+
this.checkNotDestroyed();
|
|
294
|
+
this.tagData = {
|
|
295
|
+
...this.tagData,
|
|
296
|
+
_mp4ChapterStyle: mp4ChapterStyle,
|
|
297
|
+
chapters
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
getBextData() {
|
|
301
|
+
this.checkNotDestroyed();
|
|
302
|
+
return this.tagData?.bextData ?? void 0;
|
|
303
|
+
}
|
|
304
|
+
setBextData(data) {
|
|
305
|
+
this.checkNotDestroyed();
|
|
306
|
+
this.tagData = { ...this.tagData, bextData: data };
|
|
307
|
+
}
|
|
308
|
+
getIxml() {
|
|
309
|
+
this.checkNotDestroyed();
|
|
310
|
+
const v = this.tagData?.ixml;
|
|
311
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
312
|
+
}
|
|
313
|
+
setIxml(data) {
|
|
314
|
+
this.checkNotDestroyed();
|
|
315
|
+
this.tagData = { ...this.tagData, ixml: data };
|
|
316
|
+
}
|
|
278
317
|
getRatings() {
|
|
279
318
|
this.checkNotDestroyed();
|
|
280
319
|
return this.tagData?.ratings ?? [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview WASI host loader for in-process filesystem access
|
|
3
3
|
*
|
|
4
|
-
* Loads the
|
|
4
|
+
* Loads the taglib-wasi.wasm binary with real WASI filesystem
|
|
5
5
|
* implementations, enabling efficient seek-based file I/O.
|
|
6
6
|
*/
|
|
7
7
|
import type { FileSystemProvider } from "./wasi-fs-provider.js";
|
|
@@ -22,7 +22,7 @@ async function resolveFs(provided) {
|
|
|
22
22
|
}
|
|
23
23
|
async function loadWasiHost(config) {
|
|
24
24
|
const defaultPath = (() => {
|
|
25
|
-
const url = new URL("../../
|
|
25
|
+
const url = new URL("../../taglib-wasi.wasm", import.meta.url);
|
|
26
26
|
return url.protocol === "file:" ? fileUrlToPath(url) : url.href;
|
|
27
27
|
})();
|
|
28
28
|
const wasmPath = config.wasmPath ?? defaultPath;
|