taglib-wasm 2.2.3 → 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.
- package/README.md +192 -13
- package/dist/index.browser.d.ts +24 -4
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1123 -208
- 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 +527 -202
- package/dist/src/errors/base.d.ts +17 -2
- package/dist/src/errors/base.d.ts.map +1 -1
- package/dist/src/errors/base.js +18 -0
- package/dist/src/runtime/wasi-adapter/adapter.d.ts +13 -1
- package/dist/src/runtime/wasi-adapter/adapter.d.ts.map +1 -1
- package/dist/src/runtime/wasi-adapter/adapter.js +17 -0
- package/dist/src/runtime/wasi-adapter/audio-properties.d.ts +4 -1
- package/dist/src/runtime/wasi-adapter/audio-properties.d.ts.map +1 -1
- package/dist/src/runtime/wasi-adapter/audio-properties.js +23 -6
- package/dist/src/runtime/wasi-adapter/path-open.d.ts +68 -0
- package/dist/src/runtime/wasi-adapter/path-open.d.ts.map +1 -0
- package/dist/src/runtime/wasi-adapter/path-open.js +76 -0
- package/dist/src/runtime/wasi-adapter/wasm-io.d.ts.map +1 -1
- package/dist/src/runtime/wasi-adapter/wasm-io.js +36 -28
- package/dist/src/runtime/wasi-host-loader.js +8 -3
- package/dist/src/runtime/wasmer-sdk-loader/types.d.ts +13 -0
- package/dist/src/runtime/wasmer-sdk-loader/types.d.ts.map +1 -1
- package/dist/src/simple/checksum-operations.d.ts +25 -0
- package/dist/src/simple/checksum-operations.d.ts.map +1 -0
- package/dist/src/simple/checksum-operations.js +7 -0
- package/dist/src/simple/index.d.ts +2 -0
- package/dist/src/simple/index.d.ts.map +1 -1
- package/dist/src/simple/index.js +2 -0
- package/dist/src/taglib/audio-file-checksum.d.ts +47 -0
- package/dist/src/taglib/audio-file-checksum.d.ts.map +1 -0
- package/dist/src/taglib/audio-file-checksum.js +77 -0
- package/dist/src/taglib/audio-file-impl.d.ts +4 -0
- package/dist/src/taglib/audio-file-impl.d.ts.map +1 -1
- package/dist/src/taglib/audio-file-impl.js +32 -0
- package/dist/src/taglib/audio-file-interface.d.ts +17 -0
- package/dist/src/taglib/audio-file-interface.d.ts.map +1 -1
- package/dist/src/taglib/media-ranges.d.ts +85 -0
- package/dist/src/taglib/media-ranges.d.ts.map +1 -0
- package/dist/src/taglib/media-ranges.js +192 -0
- package/dist/src/taglib/metadata-extent.d.ts +55 -0
- package/dist/src/taglib/metadata-extent.d.ts.map +1 -1
- package/dist/src/taglib/metadata-extent.js +24 -6
- package/dist/src/taglib/taglib-class.d.ts.map +1 -1
- package/dist/src/taglib/taglib-class.js +13 -24
- package/dist/src/utils/path.d.ts +12 -0
- package/dist/src/utils/path.d.ts.map +1 -1
- package/dist/src/utils/path.js +19 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/wasm.d.ts +9 -0
- 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/web.browser.d.ts +13 -0
- package/dist/web.browser.d.ts.map +1 -0
- package/dist/web.browser.js +3630 -0
- package/package.json +12 -4
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* List of audio formats supported by TagLib-Wasm
|
|
2
|
+
* List of audio formats supported by TagLib-Wasm.
|
|
3
|
+
*
|
|
4
|
+
* The prose source of truth is the README's "Supported Formats" section; this
|
|
5
|
+
* list carries every `FileType` member except `"unknown"` (src/types/audio-
|
|
6
|
+
* formats.ts), plus the extension aliases files actually carry ("M4A", "MKA")
|
|
7
|
+
* — ASF is the container of the WMA flavour the README names.
|
|
8
|
+
*
|
|
9
|
+
* Public contract: the default `supportedFormats` on `UnsupportedFormatError`
|
|
10
|
+
* (src/errors/classes.ts), and part of that error's message.
|
|
11
|
+
*
|
|
12
|
+
* This is the formats the library can read, not a promise that both backends
|
|
13
|
+
* describe all of them identically. Measured 2026-09-18 (taglib-uat8):
|
|
14
|
+
* `getFormat()` answers every member on both backends, but on Emscripten
|
|
15
|
+
* `audioProperties().containerFormat` / `.codec` still report `"unknown"` for
|
|
16
|
+
* the formats the embind sniffer cannot place (APE, DSF, DSDIFF, MPC, SHN,
|
|
17
|
+
* MOD, S3M, IT, XM); their tags and the rest of their properties load.
|
|
3
18
|
*/
|
|
4
|
-
export declare const SUPPORTED_FORMATS: readonly ["MP3", "MP4", "M4A", "FLAC", "OGG", "WAV", "MKA"];
|
|
19
|
+
export declare const SUPPORTED_FORMATS: readonly ["MP3", "AAC", "MP4", "M4A", "FLAC", "OGG", "OPUS", "OggFLAC", "SPEEX", "WAV", "AIFF", "ASF", "APE", "DSF", "DSDIFF", "WV", "MPC", "TTA", "SHN", "MOD", "S3M", "IT", "XM", "MATROSKA", "MKA"];
|
|
5
20
|
/**
|
|
6
21
|
* Error codes for programmatic error handling
|
|
7
22
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/errors/base.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/errors/base.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,iBAAiB,wMA0BpB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,GACpB,gBAAgB,GAChB,UAAU,GACV,QAAQ,GACR,aAAa,GACb,aAAa,GACb,aAAa,GACb,WAAW,CAAC;AAEhB;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAQlB,IAAI,EAAE,eAAe;aAErB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IATnD;;;;;OAKG;gBAEe,IAAI,EAAE,eAAe,EACrC,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAMpD"}
|
package/dist/src/errors/base.js
CHANGED
|
@@ -3,11 +3,29 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
const SUPPORTED_FORMATS = [
|
|
5
5
|
"MP3",
|
|
6
|
+
"AAC",
|
|
6
7
|
"MP4",
|
|
7
8
|
"M4A",
|
|
8
9
|
"FLAC",
|
|
9
10
|
"OGG",
|
|
11
|
+
"OPUS",
|
|
12
|
+
"OggFLAC",
|
|
13
|
+
"SPEEX",
|
|
10
14
|
"WAV",
|
|
15
|
+
"AIFF",
|
|
16
|
+
"ASF",
|
|
17
|
+
"APE",
|
|
18
|
+
"DSF",
|
|
19
|
+
"DSDIFF",
|
|
20
|
+
"WV",
|
|
21
|
+
"MPC",
|
|
22
|
+
"TTA",
|
|
23
|
+
"SHN",
|
|
24
|
+
"MOD",
|
|
25
|
+
"S3M",
|
|
26
|
+
"IT",
|
|
27
|
+
"XM",
|
|
28
|
+
"MATROSKA",
|
|
11
29
|
"MKA"
|
|
12
30
|
];
|
|
13
31
|
class TagLibError extends Error {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Adapts a WASI module interface to the TagLibModule interface,
|
|
5
5
|
* providing Emscripten-compatible memory access and string operations.
|
|
6
6
|
*/
|
|
7
|
-
import type { FileHandle, TagLibModule } from "../../wasm.js";
|
|
7
|
+
import type { FileHandle, TagLibModule, WasmFileHandle } from "../../wasm.js";
|
|
8
8
|
import type { WasiModule } from "../wasmer-sdk-loader/types.js";
|
|
9
9
|
export declare class WasiToTagLibAdapter implements TagLibModule {
|
|
10
10
|
private readonly wasi;
|
|
@@ -27,6 +27,18 @@ export declare class WasiToTagLibAdapter implements TagLibModule {
|
|
|
27
27
|
stringToUTF8(str: string, ptr: number, maxBytes: number): number;
|
|
28
28
|
lengthBytesUTF8(str: string): number;
|
|
29
29
|
createFileHandle(): FileHandle;
|
|
30
|
+
/**
|
|
31
|
+
* The WASI host module this adapter wraps. Path mode's content gate
|
|
32
|
+
* (taglib-j9ld) needs the host's own detector and its WASI→host path
|
|
33
|
+
* resolution, neither of which belongs on the shared `TagLibModule` surface
|
|
34
|
+
* every backend implements.
|
|
35
|
+
*/
|
|
36
|
+
get hostModule(): WasiModule;
|
|
37
|
+
/**
|
|
38
|
+
* The gated path open: `WasiFileHandle.loadFromPath` plus the content check a
|
|
39
|
+
* path needs where a buffer would be refused outright (see `path-open.ts`).
|
|
40
|
+
*/
|
|
41
|
+
loadAudioPath(wasiPath: string, displayPath: string): Promise<WasmFileHandle>;
|
|
30
42
|
version(): string;
|
|
31
43
|
addFunction(_func: any): number;
|
|
32
44
|
removeFunction(_ptr: number): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAMhE,qBAAa,mBAAoB,YAAW,YAAY;IACtD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,UAAU,EAAE,UAAU;IAKlC,UAAU,EAMM,UAAU,UAAU,CAAC;IAErC,IAAI,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAEzB;IAED,IAAI,KAAK,IAAI,SAAS,CAErB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,OAAO,IAAI,WAAW,CAEzB;IAED,IAAI,OAAO,IAAI,WAAW,CAEzB;IAED,IAAI,OAAO,IAAI,YAAY,CAE1B;IAED,IAAI,OAAO,IAAI,YAAY,CAE1B;IAED,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI7B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAe9C,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAOjC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAQhE,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIpC,gBAAgB,IAAI,UAAU;IAI9B;;;;;OAKG;IACH,IAAI,UAAU,IAAI,UAAU,CAE3B;IAED;;;OAGG;IACH,aAAa,CACX,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC;IAI1B,OAAO,IAAI,MAAM;IAIjB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM;IAM/B,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMlC,KAAK,CACH,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,MAAM,EAAE,GAClB,GAAG;IAMN,KAAK,CACH,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,GAAG,EAAE,GACX,GAAG;CAKP"}
|
|
@@ -4,6 +4,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
4
4
|
import { WasmerExecutionError } from "../wasmer-sdk-loader/types.js";
|
|
5
5
|
import { MemoryError } from "../../errors/classes.js";
|
|
6
6
|
import { WasiFileHandle } from "./file-handle.js";
|
|
7
|
+
import { openAudioPath } from "./path-open.js";
|
|
7
8
|
class WasiToTagLibAdapter {
|
|
8
9
|
constructor(wasiModule) {
|
|
9
10
|
__publicField(this, "wasi");
|
|
@@ -84,6 +85,22 @@ class WasiToTagLibAdapter {
|
|
|
84
85
|
createFileHandle() {
|
|
85
86
|
return new WasiFileHandle(this.wasi);
|
|
86
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* The WASI host module this adapter wraps. Path mode's content gate
|
|
90
|
+
* (taglib-j9ld) needs the host's own detector and its WASI→host path
|
|
91
|
+
* resolution, neither of which belongs on the shared `TagLibModule` surface
|
|
92
|
+
* every backend implements.
|
|
93
|
+
*/
|
|
94
|
+
get hostModule() {
|
|
95
|
+
return this.wasi;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The gated path open: `WasiFileHandle.loadFromPath` plus the content check a
|
|
99
|
+
* path needs where a buffer would be refused outright (see `path-open.ts`).
|
|
100
|
+
*/
|
|
101
|
+
loadAudioPath(wasiPath, displayPath) {
|
|
102
|
+
return openAudioPath(this, wasiPath, displayPath);
|
|
103
|
+
}
|
|
87
104
|
version() {
|
|
88
105
|
return this.wasi.tl_version();
|
|
89
106
|
}
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
import type { AudioProperties } from "../../types.js";
|
|
9
9
|
/** The audio-properties block of the C++ snapshot, null when absent. */
|
|
10
10
|
export declare function getAudioProperties(tagData: Record<string, unknown> | null): AudioProperties | null;
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* OGG codec sniffing from the first page payload: "OpusHead" (Opus),
|
|
13
|
+
* 0x7F"FLAC" (FLAC-in-Ogg), "Speex " (Speex), else Ogg Vorbis ("OGG").
|
|
14
|
+
*/
|
|
12
15
|
export declare function detectOggCodec(fileData: Uint8Array): string;
|
|
13
16
|
/**
|
|
14
17
|
* Format detection: container-based first (works for path and buffer modes),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-properties.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/audio-properties.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"audio-properties.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/audio-properties.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AA6CxB,wEAAwE;AACxE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACtC,eAAe,GAAG,IAAI,CA4BxB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAsB3D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,QAAQ,EAAE,UAAU,GAAG,IAAI,GAC1B,MAAM,CAyDR;AAED,4EAA4E;AAC5E,wBAAgB,KAAK,CACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,QAAQ,EAAE,UAAU,GAAG,IAAI,GAC1B,OAAO,CAYT"}
|
|
@@ -6,11 +6,25 @@ const CONTAINER_TO_FORMAT = {
|
|
|
6
6
|
OGG: "OGG",
|
|
7
7
|
WAV: "WAV",
|
|
8
8
|
AIFF: "AIFF",
|
|
9
|
+
ASF: "ASF",
|
|
10
|
+
APE: "APE",
|
|
11
|
+
DSF: "DSF",
|
|
12
|
+
DSDIFF: "DSDIFF",
|
|
9
13
|
WavPack: "WV",
|
|
14
|
+
MPC: "MPC",
|
|
10
15
|
TTA: "TTA",
|
|
11
|
-
|
|
16
|
+
Shorten: "SHN",
|
|
17
|
+
MOD: "MOD",
|
|
18
|
+
S3M: "S3M",
|
|
19
|
+
IT: "IT",
|
|
20
|
+
XM: "XM",
|
|
12
21
|
Matroska: "MATROSKA"
|
|
13
22
|
};
|
|
23
|
+
const OGG_CODEC_TO_FORMAT = {
|
|
24
|
+
Opus: "OPUS",
|
|
25
|
+
FLAC: "OggFLAC",
|
|
26
|
+
Speex: "SPEEX"
|
|
27
|
+
};
|
|
14
28
|
function getAudioProperties(tagData) {
|
|
15
29
|
if (!tagData || !("sampleRate" in tagData)) return null;
|
|
16
30
|
const d = tagData;
|
|
@@ -39,17 +53,20 @@ function detectOggCodec(fileData) {
|
|
|
39
53
|
if (segCount === void 0) return "OGG";
|
|
40
54
|
const payloadStart = 27 + segCount;
|
|
41
55
|
if (fileData.length < payloadStart + 8) return "OGG";
|
|
42
|
-
const sig =
|
|
43
|
-
|
|
44
|
-
);
|
|
45
|
-
if (sig ===
|
|
56
|
+
const sig = fileData.slice(payloadStart, payloadStart + 8);
|
|
57
|
+
const text = String.fromCharCode(...sig);
|
|
58
|
+
if (text === "OpusHead") return "OPUS";
|
|
59
|
+
if (sig[0] === 127 && sig[1] === 70 && sig[2] === 76 && sig[3] === 65 && sig[4] === 67) return "OggFLAC";
|
|
60
|
+
if (text === "Speex ") return "SPEEX";
|
|
46
61
|
return "OGG";
|
|
47
62
|
}
|
|
48
63
|
function getFormat(tagData, fileData) {
|
|
49
64
|
const container = tagData?.containerFormat;
|
|
50
65
|
if (container) {
|
|
51
66
|
const codec = tagData?.codec;
|
|
52
|
-
if (container === "OGG" && codec
|
|
67
|
+
if (container === "OGG" && codec && OGG_CODEC_TO_FORMAT[codec]) {
|
|
68
|
+
return OGG_CODEC_TO_FORMAT[codec];
|
|
69
|
+
}
|
|
53
70
|
if (CONTAINER_TO_FORMAT[container]) return CONTAINER_TO_FORMAT[container];
|
|
54
71
|
}
|
|
55
72
|
if (!fileData || fileData.length < 8) return "unknown";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gated path open for the WASI backend: `WasiFileHandle.loadFromPath` plus
|
|
3
|
+
* the content check a path needs and a buffer does not.
|
|
4
|
+
*
|
|
5
|
+
* `read_from_path` resolves the file class by *extension* first, and upstream's
|
|
6
|
+
* `MPEG::File` reports itself valid for any bytes at all (its `read()` never
|
|
7
|
+
* clears validity, `lib/taglib/taglib/mpeg/mpegfile.cpp`), so `junk.mp3` opens
|
|
8
|
+
* where the same bytes in a buffer are refused. Two independent signals say
|
|
9
|
+
* whether anything was really there, in cost order:
|
|
10
|
+
*
|
|
11
|
+
* 1. {@link statesAudioProperties} — whether the parse read an audio property
|
|
12
|
+
* out of the file. No extra I/O: the snapshot is what the open already
|
|
13
|
+
* produced. A file that states a sample rate is audio TagLib read, whatever
|
|
14
|
+
* its head looks like — which is how an MP3 behind a 4 KiB or 70 KiB APEv2
|
|
15
|
+
* tag (this repo's own corpus shapes, tests/media-checksum-corpus.test.ts)
|
|
16
|
+
* stays readable even though neither detector can see the frames behind the
|
|
17
|
+
* tag.
|
|
18
|
+
* 2. {@link hasRecognizableHead} — whether the head is content the boundary's
|
|
19
|
+
* detector knows, or opens as a buffer. This is what saves a file whose
|
|
20
|
+
* properties are legitimately absent (`lib/taglib/tests/data/segfault.wav`
|
|
21
|
+
* is 30 bytes of `RIFF`/`WAVE`; `tests/test-files/mp4/synth-multi-mdat.mp4`
|
|
22
|
+
* has `ftyp` and no `moov`) and every tag-only file, whose head *is* its tag:
|
|
23
|
+
* content is recognizable even when there is nothing to measure.
|
|
24
|
+
*
|
|
25
|
+
* A path is refused only when *both* say nothing — a zero-length file, junk
|
|
26
|
+
* bytes behind an audio extension. That is the shape of every refusal in this
|
|
27
|
+
* repo's and upstream's corpora (163 fixtures, swept by
|
|
28
|
+
* `tests/checksum-input-contract.test.ts`), and neither signal can refuse a file
|
|
29
|
+
* the buffer form accepts: every detector rule is head-based (MOD's signature at
|
|
30
|
+
* offset 1080 is the deepest, and the window clears it), the ID3v2 rule answers
|
|
31
|
+
* "MP3" rather than giving up when the tag runs past the window
|
|
32
|
+
* (`src/capi/taglib_boundary.c`, `tl_detect_format`), and a head that opens as a
|
|
33
|
+
* buffer *is* the buffer form's own verdict.
|
|
34
|
+
*
|
|
35
|
+
* The one asymmetry that survives is upstream's deliberately corrupt fixtures
|
|
36
|
+
* whose bytes still yield a property (`garbage.mp3`, `sv4_header.mpc`,
|
|
37
|
+
* `sv5_header.mpc`, `stripped.xm`): TagLib reads a header out of them, so the
|
|
38
|
+
* path form keeps accepting them exactly as it did before this change, while the
|
|
39
|
+
* buffer form's narrower magic rules refuse them. Nothing in the C detector can
|
|
40
|
+
* place SV4/SV5 MPC or junk-with-a-frame-header — see taglib-uat8 for that
|
|
41
|
+
* reachability gap — and refusing them here would mean refusing files the parse
|
|
42
|
+
* did read.
|
|
43
|
+
*/
|
|
44
|
+
import type { FileHandle, WasmFileHandle } from "../../wasm.js";
|
|
45
|
+
import type { WasiModule } from "../wasmer-sdk-loader/types.js";
|
|
46
|
+
/** The WASI backend this open runs on: its host module (where the detector and
|
|
47
|
+
* the WASI→host path resolution live, `WasiToTagLibAdapter.hostModule`) and its
|
|
48
|
+
* handle factory. */
|
|
49
|
+
export interface PathOpenHost {
|
|
50
|
+
readonly hostModule: WasiModule;
|
|
51
|
+
createFileHandle(): FileHandle;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Load an audio file by path, verifying that its content is audio.
|
|
55
|
+
*
|
|
56
|
+
* Every failure the caller can act on is distinct: `FileOperationError` for a
|
|
57
|
+
* path the host does not have (what the buffer form's own stat answers, so a
|
|
58
|
+
* typo reads the same on both backends), `InvalidFormatError` for a zero-byte
|
|
59
|
+
* file (see below) and for content the boundary could not resolve as audio, and
|
|
60
|
+
* the wasm-level errors unchanged. Either content signal above suffices; both
|
|
61
|
+
* saying nothing is a refusal.
|
|
62
|
+
*
|
|
63
|
+
* The returned handle is the library-owned one (the WASI brand asserted here,
|
|
64
|
+
* the WASI equivalent of `wrapEmbindHandle`), destroyed on any failure — the
|
|
65
|
+
* caller's `AudioFile` takes it over on success.
|
|
66
|
+
*/
|
|
67
|
+
export declare function openAudioPath(backend: PathOpenHost, wasiPath: string, displayPath: string): Promise<WasmFileHandle>;
|
|
68
|
+
//# sourceMappingURL=path-open.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-open.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/path-open.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAqBhE;;qBAEqB;AACrB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,gBAAgB,IAAI,UAAU,CAAC;CAChC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CA0CzB"}
|
|
@@ -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;
|
|
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
|
-
|
|
72
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
`error code ${errorCode}. Path: ${path}`,
|
|
203
|
+
throwForErrorCode(
|
|
204
|
+
wasi.tl_get_last_error_code(),
|
|
197
205
|
"write tags to path",
|
|
198
|
-
|
|
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;
|
|
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"}
|
|
@@ -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"}
|
package/dist/src/simple/index.js
CHANGED
|
@@ -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,
|