taglib-wasm 2.2.2 → 2.3.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 (87) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +197 -16
  3. package/dist/index.browser.d.ts +24 -4
  4. package/dist/index.browser.d.ts.map +1 -1
  5. package/dist/index.browser.js +1139 -217
  6. package/dist/index.d.ts +3 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/simple.browser.js +539 -209
  10. package/dist/src/constants/properties.d.ts +2 -2
  11. package/dist/src/constants/specialized-properties.d.ts +2 -2
  12. package/dist/src/constants/specialized-properties.js +2 -2
  13. package/dist/src/errors/base.d.ts +17 -2
  14. package/dist/src/errors/base.d.ts.map +1 -1
  15. package/dist/src/errors/base.js +18 -0
  16. package/dist/src/runtime/detector.d.ts +16 -1
  17. package/dist/src/runtime/detector.d.ts.map +1 -1
  18. package/dist/src/runtime/detector.js +58 -52
  19. package/dist/src/runtime/platform-io.d.ts +8 -0
  20. package/dist/src/runtime/platform-io.d.ts.map +1 -1
  21. package/dist/src/runtime/platform-io.js +11 -11
  22. package/dist/src/runtime/unified-loader/module-selection.d.ts +2 -2
  23. package/dist/src/runtime/unified-loader/module-selection.d.ts.map +1 -1
  24. package/dist/src/runtime/unified-loader/module-selection.js +3 -5
  25. package/dist/src/runtime/wasi-adapter/adapter.d.ts +13 -1
  26. package/dist/src/runtime/wasi-adapter/adapter.d.ts.map +1 -1
  27. package/dist/src/runtime/wasi-adapter/adapter.js +17 -0
  28. package/dist/src/runtime/wasi-adapter/audio-properties.d.ts +4 -1
  29. package/dist/src/runtime/wasi-adapter/audio-properties.d.ts.map +1 -1
  30. package/dist/src/runtime/wasi-adapter/audio-properties.js +24 -6
  31. package/dist/src/runtime/wasi-adapter/path-open.d.ts +68 -0
  32. package/dist/src/runtime/wasi-adapter/path-open.d.ts.map +1 -0
  33. package/dist/src/runtime/wasi-adapter/path-open.js +76 -0
  34. package/dist/src/runtime/wasi-adapter/wasm-io.d.ts.map +1 -1
  35. package/dist/src/runtime/wasi-adapter/wasm-io.js +36 -28
  36. package/dist/src/runtime/wasi-host-loader.js +8 -3
  37. package/dist/src/runtime/wasmer-sdk-loader/types.d.ts +13 -0
  38. package/dist/src/runtime/wasmer-sdk-loader/types.d.ts.map +1 -1
  39. package/dist/src/simple/checksum-operations.d.ts +25 -0
  40. package/dist/src/simple/checksum-operations.d.ts.map +1 -0
  41. package/dist/src/simple/checksum-operations.js +7 -0
  42. package/dist/src/simple/index.d.ts +2 -0
  43. package/dist/src/simple/index.d.ts.map +1 -1
  44. package/dist/src/simple/index.js +2 -0
  45. package/dist/src/taglib/audio-file-checksum.d.ts +47 -0
  46. package/dist/src/taglib/audio-file-checksum.d.ts.map +1 -0
  47. package/dist/src/taglib/audio-file-checksum.js +77 -0
  48. package/dist/src/taglib/audio-file-impl.d.ts +4 -0
  49. package/dist/src/taglib/audio-file-impl.d.ts.map +1 -1
  50. package/dist/src/taglib/audio-file-impl.js +34 -2
  51. package/dist/src/taglib/audio-file-interface.d.ts +17 -0
  52. package/dist/src/taglib/audio-file-interface.d.ts.map +1 -1
  53. package/dist/src/taglib/embind-adapter.d.ts.map +1 -1
  54. package/dist/src/taglib/embind-adapter.js +4 -1
  55. package/dist/src/taglib/id3v2-frames.d.ts.map +1 -1
  56. package/dist/src/taglib/id3v2-frames.js +2 -2
  57. package/dist/src/taglib/media-ranges.d.ts +85 -0
  58. package/dist/src/taglib/media-ranges.d.ts.map +1 -0
  59. package/dist/src/taglib/media-ranges.js +192 -0
  60. package/dist/src/taglib/metadata-extent.d.ts +55 -0
  61. package/dist/src/taglib/metadata-extent.d.ts.map +1 -1
  62. package/dist/src/taglib/metadata-extent.js +24 -6
  63. package/dist/src/taglib/taglib-class.d.ts.map +1 -1
  64. package/dist/src/taglib/taglib-class.js +13 -24
  65. package/dist/src/types/audio-formats.d.ts +5 -5
  66. package/dist/src/types/audio-formats.d.ts.map +1 -1
  67. package/dist/src/types/format-property-keys.d.ts +1 -1
  68. package/dist/src/types/format-property-keys.d.ts.map +1 -1
  69. package/dist/src/types/tags.d.ts +8 -1
  70. package/dist/src/types/tags.d.ts.map +1 -1
  71. package/dist/src/utils/path.d.ts +12 -0
  72. package/dist/src/utils/path.d.ts.map +1 -1
  73. package/dist/src/utils/path.js +19 -0
  74. package/dist/src/utils/tag-mapping.d.ts.map +1 -1
  75. package/dist/src/utils/tag-mapping.js +2 -0
  76. package/dist/src/version.d.ts +1 -1
  77. package/dist/src/version.js +1 -1
  78. package/dist/src/wasm.d.ts +9 -0
  79. package/dist/src/wasm.d.ts.map +1 -1
  80. package/dist/src/web-utils/data-url.d.ts.map +1 -1
  81. package/dist/src/web-utils/data-url.js +4 -2
  82. package/dist/taglib-wasi.wasm +0 -0
  83. package/dist/taglib-web.wasm +0 -0
  84. package/dist/web.browser.d.ts +13 -0
  85. package/dist/web.browser.d.ts.map +1 -0
  86. package/dist/web.browser.js +3630 -0
  87. package/package.json +19 -17
@@ -0,0 +1,76 @@
1
+ import {
2
+ FileOperationError,
3
+ InvalidFormatError
4
+ } from "../../errors/classes.js";
5
+ import { getFileSize, readPartialFileData } from "../../utils/file.js";
6
+ import { readTagsFromWasm } from "./wasm-io.js";
7
+ const TL_FORMAT_AUTO = 0;
8
+ const HEADER_WINDOW = 4096;
9
+ async function openAudioPath(backend, wasiPath, displayPath) {
10
+ const hostPath = backend.hostModule.hostPathFor(wasiPath);
11
+ if (hostPath === void 0) {
12
+ throw new FileOperationError(
13
+ "read",
14
+ "The path is outside the WASI preopens this host was created with",
15
+ displayPath
16
+ );
17
+ }
18
+ if (await getFileSize(hostPath) === 0) {
19
+ throw new InvalidFormatError(
20
+ `The file is empty. Path: ${displayPath}`
21
+ );
22
+ }
23
+ const handle = backend.createFileHandle();
24
+ try {
25
+ const loaded = handle.loadFromPath(wasiPath);
26
+ if (!loaded) {
27
+ throw new InvalidFormatError(
28
+ `Failed to load audio file. Path: ${displayPath}`
29
+ );
30
+ }
31
+ if (!await holdsAudio(backend, wasiPath, handle)) {
32
+ throw new InvalidFormatError(
33
+ `Failed to load audio file. File may be corrupted or in an unsupported format. Path: ${displayPath}`
34
+ );
35
+ }
36
+ return handle;
37
+ } catch (error) {
38
+ handle.destroy();
39
+ throw error;
40
+ }
41
+ }
42
+ async function holdsAudio(backend, wasiPath, handle) {
43
+ return statesAudioProperties(handle) || await hasRecognizableHead(backend, wasiPath);
44
+ }
45
+ function statesAudioProperties(handle) {
46
+ const audio = handle.getAudioProperties();
47
+ return audio !== null && (audio.sampleRate > 0 || audio.channels > 0 || audio.bitrate > 0 || audio.duration > 0 || audio.bitsPerSample > 0);
48
+ }
49
+ async function hasRecognizableHead(backend, wasiPath) {
50
+ const wasi = backend.hostModule;
51
+ const hostPath = wasi.hostPathFor(wasiPath);
52
+ if (hostPath === void 0) return false;
53
+ const head = await readPartialFileData(hostPath, HEADER_WINDOW, 0);
54
+ return detectsFormat(wasi, head) || opensAsBuffer(wasi, head);
55
+ }
56
+ function detectsFormat(wasi, head) {
57
+ const ptr = wasi.malloc(Math.max(head.length, 1));
58
+ try {
59
+ new Uint8Array(wasi.memory.buffer).set(head, ptr);
60
+ return wasi.tl_detect_format(ptr, head.length) !== TL_FORMAT_AUTO;
61
+ } finally {
62
+ wasi.free(ptr);
63
+ }
64
+ }
65
+ function opensAsBuffer(wasi, head) {
66
+ try {
67
+ readTagsFromWasm(wasi, head);
68
+ return true;
69
+ } catch (error) {
70
+ if (error instanceof InvalidFormatError) return false;
71
+ throw error;
72
+ }
73
+ }
74
+ export {
75
+ openAudioPath
76
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"wasm-io.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/wasm-io.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAYhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAKnD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,GACjB,UAAU,CAoCZ;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,UAAU,CA8BZ;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,GAAG,MAAM,EAC3B,EAAE,CAAC,EAAE,MAAM,GACV,aAAa,EAAE,CA8CjB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,GACnB,OAAO,CA2BT;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,WAAW,GACnB,UAAU,GAAG,IAAI,CA8BnB"}
1
+ {"version":3,"file":"wasm-io.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/wasm-io.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAahE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAyDnD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,GACjB,UAAU,CA2BZ;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,UAAU,CAqBZ;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,UAAU,GAAG,MAAM,EAC3B,EAAE,CAAC,EAAE,MAAM,GACV,aAAa,EAAE,CA0CjB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,GACnB,OAAO,CA0BT;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,WAAW,GACnB,UAAU,GAAG,IAAI,CA8BnB"}
@@ -48,13 +48,38 @@ import {
48
48
  WasmMemoryError
49
49
  } from "../wasi-memory.js";
50
50
  import {
51
+ FileOperationError,
51
52
  InvalidFormatError,
52
53
  UnsupportedFormatError
53
54
  } from "../../errors/classes.js";
54
55
  import { encodeTagData } from "../../msgpack/encoder.js";
55
56
  import { decodeMessagePack } from "../../msgpack/decoder.js";
57
+ const TL_ERROR_INVALID_INPUT = -1;
56
58
  const TL_ERROR_UNSUPPORTED_FORMAT = -2;
59
+ const TL_ERROR_MEMORY_ALLOCATION = -3;
60
+ const TL_ERROR_IO_READ = -4;
61
+ const TL_ERROR_IO_WRITE = -5;
57
62
  const TL_ERROR_PARSE_FAILED = -6;
63
+ function throwForErrorCode(errorCode, operation, where, bufferSize) {
64
+ switch (errorCode) {
65
+ case TL_ERROR_INVALID_INPUT:
66
+ case TL_ERROR_UNSUPPORTED_FORMAT:
67
+ case TL_ERROR_IO_READ:
68
+ case TL_ERROR_PARSE_FAILED:
69
+ throw new InvalidFormatError(
70
+ `File may be corrupted or in an unsupported format${where}`,
71
+ bufferSize
72
+ );
73
+ case TL_ERROR_IO_WRITE:
74
+ throw new FileOperationError("write", `Failed to write tags${where}`);
75
+ default:
76
+ throw new WasmMemoryError(
77
+ `error code ${errorCode}${where}`,
78
+ operation,
79
+ errorCode
80
+ );
81
+ }
82
+ }
58
83
  function readTagsFromWasm(wasi, buffer) {
59
84
  var _stack = [];
60
85
  try {
@@ -68,17 +93,11 @@ function readTagsFromWasm(wasi, buffer) {
68
93
  outSizePtr.ptr
69
94
  );
70
95
  if (resultPtr === 0) {
71
- const errorCode = wasi.tl_get_last_error_code();
72
- if (errorCode === TL_ERROR_UNSUPPORTED_FORMAT || errorCode === TL_ERROR_PARSE_FAILED) {
73
- throw new InvalidFormatError(
74
- "File may be corrupted or in an unsupported format",
75
- buffer.length
76
- );
77
- }
78
- throw new WasmMemoryError(
79
- `error code ${errorCode}. Buffer size: ${buffer.length} bytes`,
96
+ throwForErrorCode(
97
+ wasi.tl_get_last_error_code(),
80
98
  "read tags",
81
- errorCode
99
+ `. Buffer size: ${buffer.length} bytes`,
100
+ buffer.length
82
101
  );
83
102
  }
84
103
  const outSize = outSizePtr.readUint32();
@@ -100,16 +119,10 @@ function readTagsFromWasmPath(wasi, path) {
100
119
  const outSizePtr = arena.allocUint32();
101
120
  const resultPtr = wasi.tl_read_tags(pathAlloc.ptr, 0, 0, outSizePtr.ptr);
102
121
  if (resultPtr === 0) {
103
- const errorCode = wasi.tl_get_last_error_code();
104
- if (errorCode === TL_ERROR_UNSUPPORTED_FORMAT || errorCode === TL_ERROR_PARSE_FAILED) {
105
- throw new InvalidFormatError(
106
- `File may be corrupted or in an unsupported format. Path: ${path}`
107
- );
108
- }
109
- throw new WasmMemoryError(
110
- `error code ${errorCode}. Path: ${path}`,
122
+ throwForErrorCode(
123
+ wasi.tl_get_last_error_code(),
111
124
  "read tags from path",
112
- errorCode
125
+ `. Path: ${path}`
113
126
  );
114
127
  }
115
128
  const outSize = outSizePtr.readUint32();
@@ -156,11 +169,7 @@ function readId3v2FramesFromWasm(wasi, source, id) {
156
169
  operation: "readId3v2Frames"
157
170
  });
158
171
  }
159
- throw new WasmMemoryError(
160
- `error code ${errorCode}`,
161
- "read ID3v2 frames",
162
- errorCode
163
- );
172
+ throwForErrorCode(errorCode, "read ID3v2 frames", "");
164
173
  }
165
174
  const outSize = outSizePtr.readUint32();
166
175
  const u8 = new Uint8Array(wasi.memory.buffer);
@@ -191,11 +200,10 @@ function writeTagsToWasmPath(wasi, path, tagData) {
191
200
  outSizePtr.ptr
192
201
  );
193
202
  if (result !== 0) {
194
- const errorCode = wasi.tl_get_last_error_code();
195
- throw new WasmMemoryError(
196
- `error code ${errorCode}. Path: ${path}`,
203
+ throwForErrorCode(
204
+ wasi.tl_get_last_error_code(),
197
205
  "write tags to path",
198
- errorCode
206
+ `. Path: ${path}`
199
207
  );
200
208
  }
201
209
  return true;
@@ -2,7 +2,7 @@ import {
2
2
  createWasiImports
3
3
  } from "./wasi-host.js";
4
4
  import { TagLibError } from "../errors/base.js";
5
- import { fileUrlToPath } from "../utils/path.js";
5
+ import { fileUrlToPath, hostPathForPreopens } from "../utils/path.js";
6
6
  import { isDeno } from "./detector.js";
7
7
  class WasiHostLoadError extends TagLibError {
8
8
  constructor(message, cause) {
@@ -55,7 +55,7 @@ async function loadWasiHost(config) {
55
55
  if (instance.exports._initialize) {
56
56
  instance.exports._initialize();
57
57
  }
58
- return createWasiModuleFromInstance(instance, memory, wasiImports);
58
+ return createWasiModuleFromInstance(instance, memory, wasiImports, preopens);
59
59
  }
60
60
  async function loadWasmBinary(path, fs) {
61
61
  if (path.startsWith("http://") || path.startsWith("https://")) {
@@ -76,7 +76,7 @@ async function loadWasmBinary(path, fs) {
76
76
  );
77
77
  }
78
78
  }
79
- function createWasiModuleFromInstance(instance, memory, wasiImports) {
79
+ function createWasiModuleFromInstance(instance, memory, wasiImports, preopens) {
80
80
  const exports = instance.exports;
81
81
  function readCString(ptr) {
82
82
  if (!ptr) return "";
@@ -96,6 +96,11 @@ function createWasiModuleFromInstance(instance, memory, wasiImports) {
96
96
  tl_read_tags: (pathPtr, bufPtr, len, outSizePtr) => exports.tl_read_tags(pathPtr, bufPtr, len, outSizePtr),
97
97
  tl_read_id3v2_frames: (pathPtr, bufPtr, len, idPtr, outSizePtr) => exports.tl_read_id3v2_frames(pathPtr, bufPtr, len, idPtr, outSizePtr),
98
98
  tl_write_tags: (pathPtr, bufPtr, len, tagsPtr, tagsSz, outPtr, outSzPtr) => exports.tl_write_tags(pathPtr, bufPtr, len, tagsPtr, tagsSz, outPtr, outSzPtr),
99
+ tl_detect_format: (bufPtr, len) => exports.tl_detect_format(
100
+ bufPtr,
101
+ len
102
+ ),
103
+ hostPathFor: (wasiPath) => hostPathForPreopens(wasiPath, preopens),
99
104
  tl_get_last_error: () => exports.tl_get_last_error(),
100
105
  tl_get_last_error_code: () => exports.tl_get_last_error_code(),
101
106
  tl_clear_error: () => exports.tl_clear_error(),
@@ -16,6 +16,19 @@ export interface WasiModule {
16
16
  tl_read_tags(pathPtr: number, bufPtr: number, len: number, outSizePtr: number): number;
17
17
  tl_read_id3v2_frames(pathPtr: number, bufPtr: number, len: number, idPtr: number, outSizePtr: number): number;
18
18
  tl_write_tags(pathPtr: number, bufPtr: number, len: number, tagsPtr: number, tagsSize: number, outBufPtr: number, outSizePtr: number): number;
19
+ /**
20
+ * The boundary's content detector (`src/capi/taglib_boundary.c`), the one the
21
+ * buffer open runs before it picks a file class: a `tl_format` value, or
22
+ * `TL_FORMAT_AUTO` (0) when the bytes are not a container it knows.
23
+ */
24
+ tl_detect_format(bufPtr: number, len: number): number;
25
+ /**
26
+ * The host path behind a WASI path, resolved through the preopens this host
27
+ * was created with, or undefined when no preopen covers it. Host-side code
28
+ * cannot otherwise read a file the guest reads (`utils/path.ts` carries the
29
+ * rule); the path content gate is the only caller.
30
+ */
31
+ hostPathFor(wasiPath: string): string | undefined;
19
32
  tl_get_last_error(): number;
20
33
  tl_get_last_error_code(): number;
21
34
  tl_clear_error(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasmer-sdk-loader/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,qBAAa,oBAAqB,SAAQ,WAAW;gBACvC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM7C;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAEzB,UAAU,IAAI,MAAM,CAAC;IACrB,cAAc,IAAI,MAAM,CAAC;IAGzB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAGxB,YAAY,CACV,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IACV,oBAAoB,CAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IACV,aAAa,CACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IAGV,iBAAiB,IAAI,MAAM,CAAC;IAC5B,sBAAsB,IAAI,MAAM,CAAC;IACjC,cAAc,IAAI,IAAI,CAAC;IAGvB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;CAC5B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasmer-sdk-loader/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,qBAAa,oBAAqB,SAAQ,WAAW;gBACvC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM7C;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAEzB,UAAU,IAAI,MAAM,CAAC;IACrB,cAAc,IAAI,MAAM,CAAC;IAGzB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAGxB,YAAY,CACV,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IACV,oBAAoB,CAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IACV,aAAa,CACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC;IAEV;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtD;;;;;OAKG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAGlD,iBAAiB,IAAI,MAAM,CAAC;IAC5B,sBAAsB,IAAI,MAAM,CAAC;IACjC,cAAc,IAAI,IAAI,CAAC;IAGvB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,25 @@
1
+ import type { AudioFileInput } from "../types.js";
2
+ import type { MediaChecksum, MediaChecksumOptions } from "../taglib/audio-file-checksum.js";
3
+ /**
4
+ * Reads a checksum of an audio file's media content.
5
+ *
6
+ * The digest is of the *encoded media payload* — the bytes that are the audio,
7
+ * not the tags around them — so it survives a tag edit, with one boundary: an
8
+ * ID3v2 tag appended after a FLAC's audio is inside that payload, so editing it
9
+ * does move the hash. Formats whose payload cannot be delimited answer the
10
+ * whole file instead and say so (`source: "file"`), where a tag edit does move
11
+ * the hash.
12
+ *
13
+ * @param file - File path, Uint8Array, ArrayBuffer, or File object
14
+ * @param options - `basis: "pcm"` asks for FLAC's STREAMINFO MD5, the digest of
15
+ * the *uncompressed* stream, instead of the encoded payload's SHA-256
16
+ * @returns The hex digest, the algorithm, what it covers (`source`), and how
17
+ * many bytes were hashed
18
+ * @throws {TagLibInitializationError} If the Wasm module fails to initialize
19
+ * @throws {InvalidFormatError} If the file is corrupted or in an unsupported format
20
+ * @throws {UnsupportedFormatError} If `basis: "pcm"` is asked of a non-FLAC file
21
+ * @throws {MetadataError} If the payload cannot be walked, or the handle holds
22
+ * no bytes and no readable source
23
+ */
24
+ export declare function readMediaChecksum(file: AudioFileInput, options?: MediaChecksumOptions): Promise<MediaChecksum>;
25
+ //# sourceMappingURL=checksum-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checksum-operations.d.ts","sourceRoot":"","sources":["../../../src/simple/checksum-operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACrB,MAAM,kCAAkC,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,cAAc,EACpB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,aAAa,CAAC,CAExB"}
@@ -0,0 +1,7 @@
1
+ import { withAudioFile } from "./with-audio-file.js";
2
+ async function readMediaChecksum(file, options) {
3
+ return withAudioFile(file, (audioFile) => audioFile.mediaChecksum(options));
4
+ }
5
+ export {
6
+ readMediaChecksum
7
+ };
@@ -3,6 +3,8 @@ export { applyTags, applyTagsToFile, clearTags, isValidAudioFile, readFormat, re
3
3
  export { addPicture, applyCoverArt, applyPictures, clearPictures, findPictureByType, readCoverArt, readPictureMetadata, readPictures, replacePictureByType, } from "./picture-operations.js";
4
4
  export { editTagsBatch, readMetadata, readMetadataBatch, readPropertiesBatch, readTagsBatch, writeTagsBatch, } from "./batch-operations.js";
5
5
  export type { BatchItem, BatchOptions, BatchResult, FileMetadata, WriteTagUpdate, } from "./batch-operations.js";
6
+ export { readMediaChecksum } from "./checksum-operations.js";
7
+ export type { ChecksumAlgorithm, ChecksumSource, MediaChecksum, MediaChecksumOptions, } from "../taglib/audio-file-checksum.js";
6
8
  export type { AudioProperties, ExtendedTag, Picture, PictureType, Tag, TagInput, } from "../types.js";
7
9
  export { PICTURE_TYPE_NAMES, PICTURE_TYPE_VALUES } from "../types.js";
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/simple/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,SAAS,EACT,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,QAAQ,GACT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACX,GAAG,EACH,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/simple/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,SAAS,EACT,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,QAAQ,GACT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,oBAAoB,GACrB,MAAM,kCAAkC,CAAC;AAE1C,YAAY,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACX,GAAG,EACH,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -27,6 +27,7 @@ import {
27
27
  readTagsBatch,
28
28
  writeTagsBatch
29
29
  } from "./batch-operations.js";
30
+ import { readMediaChecksum } from "./checksum-operations.js";
30
31
  import { PICTURE_TYPE_NAMES, PICTURE_TYPE_VALUES } from "../types.js";
31
32
  export {
32
33
  PICTURE_TYPE_NAMES,
@@ -44,6 +45,7 @@ export {
44
45
  isValidAudioFile,
45
46
  readCoverArt,
46
47
  readFormat,
48
+ readMediaChecksum,
47
49
  readMetadata,
48
50
  readMetadataBatch,
49
51
  readPictureMetadata,
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @fileoverview `mediaChecksum()`: a SHA-256 of a file's *encoded media
3
+ * payload* — the bytes that are the audio, and not the tags around them — plus
4
+ * FLAC's STREAMINFO digest passthrough. Factored out of `AudioFileImpl` so the
5
+ * source rule below (what actually gets hashed) is stated exactly once.
6
+ */
7
+ import type { PlatformIO } from "../runtime/platform-io.js";
8
+ export type MediaChecksum = {
9
+ source: "audio-payload" | "file";
10
+ algorithm: "sha256";
11
+ hex: string;
12
+ bytesHashed: number;
13
+ } | {
14
+ source: "flac-streaminfo-md5";
15
+ algorithm: "md5";
16
+ hex: string;
17
+ bytesHashed: 16;
18
+ };
19
+ export interface MediaChecksumOptions {
20
+ basis?: "encoded" | "pcm";
21
+ }
22
+ /** The literal a checksum's `source` field carries, so a consumer can hold one
23
+ * without restating the values. */
24
+ export type ChecksumSource = MediaChecksum["source"];
25
+ /** The algorithm any returned checksum can carry — narrowed by `source`. */
26
+ export type ChecksumAlgorithm = MediaChecksum["algorithm"];
27
+ /**
28
+ * What the checksum needs from the open handle — module-internal, and not
29
+ * re-exported from either entry point (`ChecksumSource` above is the public name,
30
+ * and a handle descriptor must not shadow it).
31
+ */
32
+ interface ChecksumHandleSource {
33
+ /** The bytes the handle holds — a full file, a partial-load window image, or
34
+ * nothing at all when the data lives on disk (WASI path mode). */
35
+ bytes: Uint8Array;
36
+ /** The path, when the handle was opened from one. */
37
+ path?: string;
38
+ /** The File/Blob, when the handle was opened from one. */
39
+ blob?: Blob;
40
+ /** True when `bytes` is a spliced header+footer image rather than the file.
41
+ * Must be captured when the handle is created: `saveToFile()` clears the
42
+ * instance's own flag while the bytes stay spliced. */
43
+ partiallyLoaded: boolean;
44
+ }
45
+ export declare function mediaChecksum(source: ChecksumHandleSource, format: string, io: PlatformIO, options?: MediaChecksumOptions): Promise<MediaChecksum>;
46
+ export {};
47
+ //# sourceMappingURL=audio-file-checksum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-file-checksum.d.ts","sourceRoot":"","sources":["../../../src/taglib/audio-file-checksum.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAG5D,MAAM,MAAM,aAAa,GACrB;IACA,MAAM,EAAE,eAAe,GAAG,MAAM,CAAC;IACjC,SAAS,EAAE,QAAQ,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB,GACC;IACA,MAAM,EAAE,qBAAqB,CAAC;IAC9B,SAAS,EAAE,KAAK,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,EAAE,CAAC;CACjB,CAAC;AAEJ,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;CAC3B;AAED;mCACmC;AACnC,MAAM,MAAM,cAAc,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;AAErD,4EAA4E;AAC5E,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;AAE3D;;;;GAIG;AACH,UAAU,oBAAoB;IAC5B;sEACkE;IAClE,KAAK,EAAE,UAAU,CAAC;IAClB,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;;2DAEuD;IACvD,eAAe,EAAE,OAAO,CAAC;CAC1B;AA6FD,wBAAsB,aAAa,CACjC,MAAM,EAAE,oBAAoB,EAC5B,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,UAAU,EACd,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,CAoExB"}
@@ -0,0 +1,77 @@
1
+ import { flacStreamInfoMd5, mediaRanges } from "./media-ranges.js";
2
+ import { MetadataError, UnsupportedFormatError } from "../errors.js";
3
+ const STREAMINFO_WINDOW = 65536;
4
+ async function fileBytes(source, io) {
5
+ if (source.path) return await io.readFile(source.path);
6
+ if (source.blob) return new Uint8Array(await source.blob.arrayBuffer());
7
+ if (!source.partiallyLoaded && source.bytes.length > 0) return source.bytes;
8
+ throw new MetadataError(
9
+ "read",
10
+ "the handle holds no file bytes and has no readable source; a partial handle that has been saved drops its source \u2014 checksum the saved path instead"
11
+ );
12
+ }
13
+ function joinRanges(bytes, ranges) {
14
+ const total = ranges.reduce((n, r) => n + r.length, 0);
15
+ const overrun = ranges.find((r) => r.offset + r.length > bytes.length);
16
+ if (overrun || total > bytes.length) {
17
+ throw new MetadataError(
18
+ "read",
19
+ `range walk overran the buffer (${overrun ? `range ${overrun.offset}+${overrun.length}` : `${total} bytes`} past the ${bytes.length}-byte buffer)`
20
+ );
21
+ }
22
+ if (ranges.length === 1) {
23
+ const only = ranges[0];
24
+ const view = bytes.subarray(only.offset, only.offset + only.length);
25
+ return view.buffer instanceof ArrayBuffer ? view : new Uint8Array(view);
26
+ }
27
+ const out = new Uint8Array(total);
28
+ let at = 0;
29
+ for (const r of ranges) {
30
+ out.set(bytes.subarray(r.offset, r.offset + r.length), at);
31
+ at += r.length;
32
+ }
33
+ return out;
34
+ }
35
+ async function mediaChecksum(source, format, io, options = {}) {
36
+ if (options.basis === "pcm") {
37
+ if (format.toUpperCase() !== "FLAC") {
38
+ throw new UnsupportedFormatError(format, ["FLAC"], {
39
+ operation: "media checksum (basis: pcm)"
40
+ });
41
+ }
42
+ const windowed = source.bytes.length > 0 ? source.bytes : source.path && io.readPartial ? await io.readPartial(source.path, STREAMINFO_WINDOW, 0) : void 0;
43
+ let md5 = windowed === void 0 ? void 0 : flacStreamInfoMd5(windowed);
44
+ if (md5 === void 0 && windowed !== source.bytes) {
45
+ md5 = flacStreamInfoMd5(await fileBytes(source, io));
46
+ }
47
+ if (md5 === void 0) {
48
+ throw new MetadataError(
49
+ "read",
50
+ "STREAMINFO digest unavailable"
51
+ );
52
+ }
53
+ return {
54
+ source: "flac-streaminfo-md5",
55
+ algorithm: "md5",
56
+ hex: md5,
57
+ bytesHashed: 16
58
+ };
59
+ }
60
+ const bytes = await fileBytes(source, io);
61
+ const walk = mediaRanges(format, bytes);
62
+ const payload = joinRanges(bytes, walk.ranges);
63
+ const digest = new Uint8Array(
64
+ await crypto.subtle.digest("SHA-256", payload)
65
+ );
66
+ let hex = "";
67
+ for (const byte of digest) hex += byte.toString(16).padStart(2, "0");
68
+ return {
69
+ source: walk.kind === "ranges" ? "audio-payload" : "file",
70
+ algorithm: "sha256",
71
+ hex,
72
+ bytesHashed: payload.length
73
+ };
74
+ }
75
+ export {
76
+ mediaChecksum
77
+ };
@@ -6,6 +6,7 @@ import type { Id3v2Frame, Rating, UnsyncedLyrics } from "../constants/complex-pr
6
6
  import { type NormalizedRating } from "../utils/rating.js";
7
7
  import type { AudioFile } from "./audio-file-interface.js";
8
8
  import { BaseAudioFileImpl } from "./audio-file-base.js";
9
+ import { type MediaChecksum, type MediaChecksumOptions } from "./audio-file-checksum.js";
9
10
  /** @internal Exported for unit tests (tests/node-fs-acquisition.test.ts). */
10
11
  export declare function readFileSync(path: string): Uint8Array;
11
12
  /**
@@ -16,9 +17,12 @@ export declare function readFileSync(path: string): Uint8Array;
16
17
  */
17
18
  export declare class AudioFileImpl extends BaseAudioFileImpl implements AudioFile {
18
19
  private pathModeBuffer;
20
+ /** How the handle was loaded — `isPartiallyLoaded` is mutated by saveToFile(). */
21
+ private readonly partiallyLoadedAtConstruction;
19
22
  constructor(module: TagLibModule, fileHandle: WasmFileHandle, sourcePath?: string, originalSource?: string | Uint8Array | ArrayBuffer | File, isPartiallyLoaded?: boolean, partialLoadOptions?: OpenOptions);
20
23
  save(): boolean;
21
24
  getFileBuffer(): Uint8Array;
25
+ mediaChecksum(options?: MediaChecksumOptions): Promise<MediaChecksum>;
22
26
  saveToFile(path?: string): Promise<void>;
23
27
  getPictures(): Picture[];
24
28
  setPictures(pictures: Picture[]): void;
@@ -1 +1 @@
1
- {"version":3,"file":"audio-file-impl.d.ts","sourceRoot":"","sources":["../../../src/taglib/audio-file-impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAIV,YAAY,EACZ,cAAc,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,EACV,UAAU,EACV,MAAM,EACN,cAAc,EACf,MAAM,oCAAoC,CAAC;AAc5C,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAoBzD,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CASrD;AAED;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,iBAAkB,YAAW,SAAS;IACvE,OAAO,CAAC,cAAc,CAA2B;gBAG/C,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,cAAc,EAC1B,UAAU,CAAC,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,IAAI,EACzD,iBAAiB,GAAE,OAAe,EAClC,kBAAkB,CAAC,EAAE,WAAW;IAYlC,IAAI,IAAI,OAAO;IAef,aAAa,IAAI,UAAU;IA2BrB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4D9C,WAAW,IAAI,OAAO,EAAE;IAYxB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI;IAStC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IASlC,cAAc,IAAI,IAAI;IAItB,WAAW,IAAI,OAAO,EAAE;IAqBxB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAuBpE,OAAO,IAAI,uBAAuB,GAAG,SAAS;IAI9C,OAAO,CAAC,IAAI,EAAE,uBAAuB,GAAG,IAAI;IAI5C,WAAW,IAAI,UAAU,GAAG,SAAS;IAIrC,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAI1C,OAAO,IAAI,MAAM,GAAG,SAAS;IAI7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIlC,UAAU,IAAI,MAAM,EAAE;IAWtB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAQnC,SAAS,IAAI,cAAc,EAAE;IAS7B,SAAS,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI;IAQzC,SAAS,IAAI,gBAAgB,GAAG,SAAS;IAKzC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ/C,cAAc,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAMzC,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI;IAOpD,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMnC,UAAU,IAAI;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,EAAE,EAAE,OAAO,CAAA;KAAE;IAI1C,YAAY,CAAC,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,EAAE,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;CAM1D"}
1
+ {"version":3,"file":"audio-file-impl.d.ts","sourceRoot":"","sources":["../../../src/taglib/audio-file-impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAIV,YAAY,EACZ,cAAc,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,EACV,UAAU,EACV,MAAM,EACN,cAAc,EACf,MAAM,oCAAoC,CAAC;AAc5C,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAqBlC,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CASrD;AAED;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,iBAAkB,YAAW,SAAS;IACvE,OAAO,CAAC,cAAc,CAA2B;IACjD,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAU;gBAGtD,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,cAAc,EAC1B,UAAU,CAAC,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,IAAI,EACzD,iBAAiB,GAAE,OAAe,EAClC,kBAAkB,CAAC,EAAE,WAAW;IAalC,IAAI,IAAI,OAAO;IAef,aAAa,IAAI,UAAU;IA2B3B,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;IA2B/D,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4D9C,WAAW,IAAI,OAAO,EAAE;IAYxB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI;IAStC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IASlC,cAAc,IAAI,IAAI;IAItB,WAAW,IAAI,OAAO,EAAE;IAqBxB,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI;IA0BpE,OAAO,IAAI,uBAAuB,GAAG,SAAS;IAI9C,OAAO,CAAC,IAAI,EAAE,uBAAuB,GAAG,IAAI;IAI5C,WAAW,IAAI,UAAU,GAAG,SAAS;IAIrC,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAI1C,OAAO,IAAI,MAAM,GAAG,SAAS;IAI7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIlC,UAAU,IAAI,MAAM,EAAE;IAWtB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAQnC,SAAS,IAAI,cAAc,EAAE;IAS7B,SAAS,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI;IAQzC,SAAS,IAAI,gBAAgB,GAAG,SAAS;IAKzC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ/C,cAAc,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAMzC,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI;IAOpD,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMnC,UAAU,IAAI;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,EAAE,EAAE,OAAO,CAAA;KAAE;IAI1C,YAAY,CAAC,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,EAAE,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;CAM1D"}
@@ -19,6 +19,10 @@ import { getNodeFsSync } from "../utils/node-fs.js";
19
19
  import { normalized } from "../utils/rating.js";
20
20
  import { isDeno } from "../runtime/detector.js";
21
21
  import { BaseAudioFileImpl } from "./audio-file-base.js";
22
+ import {
23
+ mediaChecksum
24
+ } from "./audio-file-checksum.js";
25
+ import { getPlatformIO } from "../runtime/platform-io.js";
22
26
  import { saveViaFreshHandle } from "./save-reconstruct.js";
23
27
  function sortChapters(list) {
24
28
  return [...list].sort((a, b) => a.startTimeMs - b.startTimeMs);
@@ -50,6 +54,9 @@ class AudioFileImpl extends BaseAudioFileImpl {
50
54
  partialLoadOptions
51
55
  );
52
56
  __publicField(this, "pathModeBuffer", null);
57
+ /** How the handle was loaded — `isPartiallyLoaded` is mutated by saveToFile(). */
58
+ __publicField(this, "partiallyLoadedAtConstruction");
59
+ this.partiallyLoadedAtConstruction = isPartiallyLoaded;
53
60
  }
54
61
  save() {
55
62
  if (this.isPartiallyLoaded && this.originalSource) {
@@ -85,6 +92,31 @@ class AudioFileImpl extends BaseAudioFileImpl {
85
92
  "No file data available: in-memory buffer is empty and no source path is set"
86
93
  );
87
94
  }
95
+ mediaChecksum(options) {
96
+ return mediaChecksum(
97
+ {
98
+ // The cheap, no-IO accessor — `getFileBuffer()` would read the whole
99
+ // file from disk in path mode (and cache it), which the source rule is
100
+ // about to read for itself.
101
+ bytes: this.handle.getBuffer(),
102
+ // empty in path mode: the data is on disk
103
+ // Both optional fields are conditional: they are `undefined` far more
104
+ // often than not, and `exactOptionalPropertyTypes` refuses an explicit
105
+ // `undefined` on an optional property.
106
+ ...this.sourcePath !== void 0 ? { path: this.sourcePath } : {},
107
+ // originalSource is the File when the caller passed one. A partial File
108
+ // has no path, so this is the only way back to the real bytes.
109
+ ...this.originalSource instanceof Blob ? { blob: this.originalSource } : {},
110
+ // Captured at construction, NOT this.isPartiallyLoaded: saveToFile() sets
111
+ // that flag false (and clears originalSource) while the handle still holds
112
+ // the spliced image, which would make the source rule hash the image.
113
+ partiallyLoaded: this.partiallyLoadedAtConstruction
114
+ },
115
+ this.getFormat(),
116
+ getPlatformIO(),
117
+ options
118
+ );
119
+ }
88
120
  async saveToFile(path) {
89
121
  const targetPath = path ?? this.sourcePath;
90
122
  if (!targetPath) {
@@ -174,8 +206,8 @@ class AudioFileImpl extends BaseAudioFileImpl {
174
206
  }
175
207
  setChapters(chapters, options) {
176
208
  const fmt = this.getFormat();
177
- if (fmt !== "MP3" && fmt !== "MP4") {
178
- throw new UnsupportedFormatError(fmt, ["MP3", "MP4"], {
209
+ if (fmt !== "MP3" && fmt !== "AAC" && fmt !== "MP4") {
210
+ throw new UnsupportedFormatError(fmt, ["MP3", "AAC", "MP4"], {
179
211
  operation: "setChapters"
180
212
  });
181
213
  }
@@ -2,6 +2,7 @@ import type { AudioProperties, FileType, Picture, PropertyMap } from "../types.j
2
2
  import type { TypedAudioProperties } from "../types/audio-formats.js";
3
3
  import type { Id3v2Frame, Rating, UnsyncedLyrics } from "../constants/complex-properties.js";
4
4
  import type { MutableTag } from "./mutable-tag.js";
5
+ import type { MediaChecksum, MediaChecksumOptions } from "./audio-file-checksum.js";
5
6
  import type { FormatPropertyKey } from "../types/format-property-keys.js";
6
7
  import type { NormalizedRating } from "../utils/rating.js";
7
8
  /**
@@ -66,6 +67,22 @@ export interface AudioFile {
66
67
  * and cannot be read back — never returns an empty buffer on failure.
67
68
  */
68
69
  getFileBuffer(): Uint8Array;
70
+ /**
71
+ * SHA-256 of the file's encoded media payload — the bytes that are the audio,
72
+ * not the tags around them — so the digest survives a tag edit, with one
73
+ * boundary: an ID3v2 tag appended after a FLAC's audio is inside the payload,
74
+ * so editing it does move the hash. Formats whose payload cannot be delimited
75
+ * answer the whole file instead and say so (`source: "file"`), where a tag
76
+ * edit does move the hash.
77
+ *
78
+ * Pass `{ basis: "pcm" }` for FLAC's STREAMINFO MD5 — the digest of the
79
+ * *uncompressed* stream, read straight from the file's first metadata block.
80
+ * Other formats throw {@link UnsupportedFormatError}.
81
+ *
82
+ * @throws {MetadataError} If the handle holds no file bytes and has no
83
+ * readable source (a partial handle that has already been saved).
84
+ */
85
+ mediaChecksum(options?: MediaChecksumOptions): Promise<MediaChecksum>;
69
86
  /**
70
87
  * Save all changes to a file on disk.
71
88
  * @param path - Optional file path. If not provided, saves to the original path.
@@ -1 +1 @@
1
- {"version":3,"file":"audio-file-interface.d.ts","sourceRoot":"","sources":["../../../src/taglib/audio-file-interface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audio-file-interface.d.ts","sourceRoot":"","sources":["../../../src/taglib/audio-file-interface.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"embind-adapter.d.ts","sourceRoot":"","sources":["../../../src/taglib/embind-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAyB,cAAc,EAAE,MAAM,YAAY,CAAC;AAcxE,wEAAwE;AACxE,UAAU,gBAAgB;IACxB,KAAK,IAAI,MAAM,CAAC;IAChB,MAAM,IAAI,MAAM,CAAC;IACjB,KAAK,IAAI,MAAM,CAAC;IAChB,OAAO,IAAI,MAAM,CAAC;IAClB,KAAK,IAAI,MAAM,CAAC;IAChB,IAAI,IAAI,MAAM,CAAC;IACf,KAAK,IAAI,MAAM,CAAC;IAChB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,oFAAoF;AACpF,UAAU,4BAA4B;IACpC,eAAe,IAAI,MAAM,CAAC;IAC1B,oBAAoB,IAAI,MAAM,CAAC;IAC/B,OAAO,IAAI,MAAM,CAAC;IAClB,UAAU,IAAI,MAAM,CAAC;IACrB,QAAQ,IAAI,MAAM,CAAC;IACnB,aAAa,IAAI,MAAM,CAAC;IACxB,KAAK,IAAI,MAAM,CAAC;IAChB,eAAe,IAAI,MAAM,CAAC;IAC1B,UAAU,IAAI,OAAO,CAAC;IACtB,WAAW,IAAI,MAAM,CAAC;IACtB,SAAS,IAAI,MAAM,CAAC;IACpB,WAAW,IAAI,OAAO,CAAC;IACvB,aAAa,IAAI,MAAM,CAAC;IACxB,WAAW,IAAI,MAAM,CAAC;IACtB,YAAY,IAAI,MAAM,CAAC;CACxB;AAED,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,IAAI,gBAAgB,CAAC;IAC3B,kBAAkB,IAAI,4BAA4B,GAAG,IAAI,CAAC;IAC1D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,cAAc,CAoKtE"}
1
+ {"version":3,"file":"embind-adapter.d.ts","sourceRoot":"","sources":["../../../src/taglib/embind-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAyB,cAAc,EAAE,MAAM,YAAY,CAAC;AAcxE,wEAAwE;AACxE,UAAU,gBAAgB;IACxB,KAAK,IAAI,MAAM,CAAC;IAChB,MAAM,IAAI,MAAM,CAAC;IACjB,KAAK,IAAI,MAAM,CAAC;IAChB,OAAO,IAAI,MAAM,CAAC;IAClB,KAAK,IAAI,MAAM,CAAC;IAChB,IAAI,IAAI,MAAM,CAAC;IACf,KAAK,IAAI,MAAM,CAAC;IAChB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,oFAAoF;AACpF,UAAU,4BAA4B;IACpC,eAAe,IAAI,MAAM,CAAC;IAC1B,oBAAoB,IAAI,MAAM,CAAC;IAC/B,OAAO,IAAI,MAAM,CAAC;IAClB,UAAU,IAAI,MAAM,CAAC;IACrB,QAAQ,IAAI,MAAM,CAAC;IACnB,aAAa,IAAI,MAAM,CAAC;IACxB,KAAK,IAAI,MAAM,CAAC;IAChB,eAAe,IAAI,MAAM,CAAC;IAC1B,UAAU,IAAI,OAAO,CAAC;IACtB,WAAW,IAAI,MAAM,CAAC;IACtB,SAAS,IAAI,MAAM,CAAC;IACpB,WAAW,IAAI,OAAO,CAAC;IACvB,aAAa,IAAI,MAAM,CAAC;IACxB,WAAW,IAAI,MAAM,CAAC;IACtB,YAAY,IAAI,MAAM,CAAC;CACxB;AAED,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,IAAI,gBAAgB,CAAC;IAC3B,kBAAkB,IAAI,4BAA4B,GAAG,IAAI,CAAC;IAC1D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,cAAc,CAyKtE"}
@@ -121,7 +121,10 @@ function wrapEmbindHandle(raw) {
121
121
  ...containerFormat === "MP4" || containerFormat === "ASF" ? { isEncrypted: pw.isEncrypted() } : {},
122
122
  ...formatVersion > 0 ? { formatVersion } : {},
123
123
  ...isValidBitrateMode(bitrateMode) ? { bitrateMode } : {},
124
- ...codec === "Opus" ? { outputGainDb: pw.outputGainDb() } : {}
124
+ // OpusHead gain exists only in an Ogg Opus stream. Gating on codec
125
+ // alone fabricated outputGainDb: 0 for MP4 tracks once the MP4 codec
126
+ // enum was mapped (the WASI side never emitted it there) — taglib-kswf.
127
+ ...containerFormat === "OGG" && codec === "Opus" ? { outputGainDb: pw.outputGainDb() } : {}
125
128
  };
126
129
  }
127
130
  };
@@ -1 +1 @@
1
- {"version":3,"file":"id3v2-frames.d.ts","sourceRoot":"","sources":["../../../src/taglib/id3v2-frames.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAIrE,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAM9C;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAQ3E;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,CAUtE;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,CAM9D"}
1
+ {"version":3,"file":"id3v2-frames.d.ts","sourceRoot":"","sources":["../../../src/taglib/id3v2-frames.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAIrE,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAQ9C;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAQ3E;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,CAUtE;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,CAM9D"}