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.
Files changed (53) hide show
  1. package/README.md +512 -38
  2. package/dist/index.browser.js +275 -3
  3. package/dist/index.d.ts +2 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +2 -0
  6. package/dist/simple.browser.js +275 -3
  7. package/dist/src/bwf/bext.d.ts +28 -0
  8. package/dist/src/bwf/bext.d.ts.map +1 -0
  9. package/dist/src/bwf/bext.js +126 -0
  10. package/dist/src/msgpack/encoder.d.ts.map +1 -1
  11. package/dist/src/msgpack/encoder.js +9 -1
  12. package/dist/src/runtime/unified-loader/module-loading.js +1 -1
  13. package/dist/src/runtime/wasi-adapter/file-handle.d.ts +7 -1
  14. package/dist/src/runtime/wasi-adapter/file-handle.d.ts.map +1 -1
  15. package/dist/src/runtime/wasi-adapter/file-handle.js +41 -2
  16. package/dist/src/runtime/wasi-host-loader.d.ts +1 -1
  17. package/dist/src/runtime/wasi-host-loader.js +1 -1
  18. package/dist/src/taglib/audio-file-bwf.d.ts +14 -0
  19. package/dist/src/taglib/audio-file-bwf.d.ts.map +1 -0
  20. package/dist/src/taglib/audio-file-bwf.js +41 -0
  21. package/dist/src/taglib/audio-file-impl.d.ts +10 -0
  22. package/dist/src/taglib/audio-file-impl.d.ts.map +1 -1
  23. package/dist/src/taglib/audio-file-impl.js +65 -1
  24. package/dist/src/taglib/audio-file-interface.d.ts +27 -0
  25. package/dist/src/taglib/audio-file-interface.d.ts.map +1 -1
  26. package/dist/src/taglib/embind-adapter.d.ts +2 -0
  27. package/dist/src/taglib/embind-adapter.d.ts.map +1 -1
  28. package/dist/src/taglib/embind-adapter.js +27 -2
  29. package/dist/src/types/audio-formats.d.ts +18 -0
  30. package/dist/src/types/audio-formats.d.ts.map +1 -1
  31. package/dist/src/types/bwf.d.ts +43 -0
  32. package/dist/src/types/bwf.d.ts.map +1 -0
  33. package/dist/src/types/bwf.js +0 -0
  34. package/dist/src/types/chapters.d.ts +47 -0
  35. package/dist/src/types/chapters.d.ts.map +1 -0
  36. package/dist/src/types/chapters.js +0 -0
  37. package/dist/src/types/index.d.ts +2 -0
  38. package/dist/src/types/index.d.ts.map +1 -1
  39. package/dist/src/types/index.js +2 -0
  40. package/dist/src/types/metadata-mappings.d.ts +1 -1
  41. package/dist/src/types/metadata-mappings.d.ts.map +1 -1
  42. package/dist/src/types/tags.d.ts +11 -7
  43. package/dist/src/types/tags.d.ts.map +1 -1
  44. package/dist/src/version.d.ts +1 -1
  45. package/dist/src/version.js +1 -1
  46. package/dist/src/wasm.d.ts +14 -2
  47. package/dist/src/wasm.d.ts.map +1 -1
  48. package/dist/taglib-wasi.wasm +0 -0
  49. package/dist/taglib-web.wasm +0 -0
  50. package/dist/taglib-wrapper.d.ts +0 -2
  51. package/dist/taglib-wrapper.js +1 -1
  52. package/package.json +5 -5
  53. package/dist/taglib_wasi.wasm +0 -0
@@ -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: pw.codec() || "unknown",
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.1.2";
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;AAcrB,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
+ {"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(["pictures", "ratings", "lyrics", "chapters"]);
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("../../../taglib_wasi.wasm");
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;AAC5D,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;AAqDhE,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;IA4B5C,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,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"}
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(["pictures", "ratings"]);
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 taglib_wasi.wasm binary with real WASI filesystem
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("../../taglib_wasi.wasm", import.meta.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;