taglib-wasm 1.5.2 → 1.6.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/LICENSE +12 -9
- package/README.md +6 -3
- package/dist/index.browser.js +255 -85
- package/dist/index.d.ts +1 -1
- package/dist/simple.browser.js +253 -84
- package/dist/src/constants/complex-properties.d.ts +18 -12
- package/dist/src/constants/complex-properties.d.ts.map +1 -1
- package/dist/src/constants/properties.d.ts +24 -0
- package/dist/src/constants/properties.d.ts.map +1 -1
- package/dist/src/constants/properties.js +34 -0
- package/dist/src/constants/specialized-properties.d.ts +23 -0
- package/dist/src/constants/specialized-properties.d.ts.map +1 -1
- package/dist/src/constants/specialized-properties.js +20 -0
- package/dist/src/constants/tags.d.ts.map +1 -1
- package/dist/src/constants/tags.js +2 -1
- package/dist/src/deno-compile.d.ts +12 -0
- package/dist/src/deno-compile.d.ts.map +1 -1
- package/dist/src/deno-compile.js +9 -8
- package/dist/src/msgpack/encoder.d.ts.map +1 -1
- package/dist/src/msgpack/encoder.js +6 -4
- package/dist/src/runtime/detector.d.ts +0 -6
- package/dist/src/runtime/detector.d.ts.map +1 -1
- package/dist/src/runtime/detector.js +1 -14
- package/dist/src/runtime/wasi-adapter/file-handle.d.ts +2 -0
- package/dist/src/runtime/wasi-adapter/file-handle.d.ts.map +1 -1
- package/dist/src/runtime/wasi-adapter/file-handle.js +61 -52
- package/dist/src/taglib/audio-file-base.d.ts.map +1 -1
- package/dist/src/taglib/audio-file-base.js +33 -77
- package/dist/src/taglib/mp4-item-names.d.ts +12 -0
- package/dist/src/taglib/mp4-item-names.d.ts.map +1 -0
- package/dist/src/taglib/mp4-item-names.js +4 -0
- package/dist/src/taglib/mutable-tag-impl.d.ts +14 -0
- package/dist/src/taglib/mutable-tag-impl.d.ts.map +1 -0
- package/dist/src/taglib/mutable-tag-impl.js +88 -0
- package/dist/src/taglib/save-reconstruct.d.ts.map +1 -1
- package/dist/src/taglib/save-reconstruct.js +4 -0
- package/dist/src/types/metadata-mappings.d.ts.map +1 -1
- package/dist/src/types/metadata-mappings.js +14 -0
- package/dist/src/types/tags.d.ts +16 -0
- package/dist/src/types/tags.d.ts.map +1 -1
- package/dist/src/utils/mirror-fields.d.ts +79 -0
- package/dist/src/utils/mirror-fields.d.ts.map +1 -0
- package/dist/src/utils/mirror-fields.js +67 -0
- package/dist/src/utils/tag-mapping.d.ts.map +1 -1
- package/dist/src/utils/tag-mapping.js +47 -5
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/taglib-wasi.wasm +0 -0
- package/dist/taglib-web.wasm +0 -0
- package/dist/taglib-wrapper.js +1 -1
- package/package.json +8 -5
|
@@ -123,6 +123,26 @@ const SPECIALIZED_PROPERTIES = {
|
|
|
123
123
|
vorbis: "ITUNNORM",
|
|
124
124
|
mp4: "----:com.apple.iTunes:iTunNORM"
|
|
125
125
|
}
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Apple gapless-playback data (encoder delay, padding, original sample count).
|
|
129
|
+
*
|
|
130
|
+
* Exists so the two Apple freeform atoms are presented consistently: without
|
|
131
|
+
* it, `properties()` answered `appleSoundCheck` for iTunNORM but the raw
|
|
132
|
+
* uppercased `ITUNSMPB` for its sibling, because only one had an alias. The
|
|
133
|
+
* name mirrors `appleSoundCheck` — vendor-prefixed, feature-named rather than
|
|
134
|
+
* atom-named (tuneup-ibo).
|
|
135
|
+
*/
|
|
136
|
+
appleGaplessInfo: {
|
|
137
|
+
key: "ITUNSMPB",
|
|
138
|
+
description: "Apple gapless playback data (encoder delay and padding)",
|
|
139
|
+
type: "string",
|
|
140
|
+
supportedFormats: ["ID3v2", "MP4", "Vorbis"],
|
|
141
|
+
mappings: {
|
|
142
|
+
id3v2: { frame: "TXXX", description: "iTunSMPB" },
|
|
143
|
+
vorbis: "ITUNSMPB",
|
|
144
|
+
mp4: "----:com.apple.iTunes:iTunSMPB"
|
|
145
|
+
}
|
|
126
146
|
}
|
|
127
147
|
};
|
|
128
148
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../../src/constants/tags.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFP,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../../src/constants/tags.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFP,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;AAYrD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,OAAO,CAE5D;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,SAAS,OAAO,EAAE,CAEnD"}
|
|
@@ -72,8 +72,9 @@ const Tags = {
|
|
|
72
72
|
InvolvedPeople: "involvedPeople",
|
|
73
73
|
Encoding: "encoding"
|
|
74
74
|
};
|
|
75
|
+
const VALID_TAG_NAMES = new Set(Object.values(Tags));
|
|
75
76
|
function isValidTagName(name) {
|
|
76
|
-
return
|
|
77
|
+
return VALID_TAG_NAMES.has(name);
|
|
77
78
|
}
|
|
78
79
|
function getAllTagNames() {
|
|
79
80
|
return Object.values(Tags);
|
|
@@ -8,6 +8,18 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { TagLib } from "./taglib.js";
|
|
10
10
|
export { isDenoCompiled } from "./runtime/deno-detect.js";
|
|
11
|
+
/**
|
|
12
|
+
* Where {@link prepareWasmForEmbedding} looks for the Emscripten binary, in
|
|
13
|
+
* order, resolved relative to this module.
|
|
14
|
+
*
|
|
15
|
+
* `build/` comes first deliberately: it holds the committed, authoritative
|
|
16
|
+
* artifact, while `dist/` is gitignored scratch that only the npm chain
|
|
17
|
+
* (`build:copy-wasm`/`postbuild`) refreshes. A stale `dist/` in a working
|
|
18
|
+
* checkout would otherwise silently shadow a freshly built binary. Published
|
|
19
|
+
* packages ship no `build/` (it is absent from package.json's `files`), so
|
|
20
|
+
* resolution there falls through to `dist/` exactly as before.
|
|
21
|
+
*/
|
|
22
|
+
export declare const WASM_EMBED_SEARCH_PATHS: readonly string[];
|
|
11
23
|
/**
|
|
12
24
|
* Initialize TagLib with automatic handling for Deno compiled binaries.
|
|
13
25
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno-compile.d.ts","sourceRoot":"","sources":["../../src/deno-compile.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,wBAAwB,CAC5C,gBAAgB,SAAsB,GACrC,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,SAAsB,GAC/B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"deno-compile.d.ts","sourceRoot":"","sources":["../../src/deno-compile.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAIpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,wBAAwB,CAC5C,gBAAgB,SAAsB,GACrC,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,SAAsB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAuCf"}
|
package/dist/src/deno-compile.js
CHANGED
|
@@ -3,6 +3,11 @@ import { FileOperationError } from "./errors/classes.js";
|
|
|
3
3
|
import { isDenoCompiled } from "./runtime/deno-detect.js";
|
|
4
4
|
import { fileUrlToPath } from "./utils/path.js";
|
|
5
5
|
import { isDenoCompiled as isDenoCompiled2 } from "./runtime/deno-detect.js";
|
|
6
|
+
const WASM_EMBED_SEARCH_PATHS = [
|
|
7
|
+
"../build/taglib-web.wasm",
|
|
8
|
+
"../dist/taglib-web.wasm",
|
|
9
|
+
"./node_modules/taglib-wasm/dist/taglib-web.wasm"
|
|
10
|
+
];
|
|
6
11
|
async function initializeForDenoCompile(embeddedWasmPath = "./taglib-web.wasm") {
|
|
7
12
|
if (isDenoCompiled()) {
|
|
8
13
|
const strategies = [
|
|
@@ -30,14 +35,9 @@ async function initializeForDenoCompile(embeddedWasmPath = "./taglib-web.wasm")
|
|
|
30
35
|
}
|
|
31
36
|
async function prepareWasmForEmbedding(outputPath = "./taglib-web.wasm") {
|
|
32
37
|
try {
|
|
33
|
-
const possiblePaths =
|
|
34
|
-
new URL(
|
|
35
|
-
|
|
36
|
-
new URL(
|
|
37
|
-
"./node_modules/taglib-wasm/dist/taglib-web.wasm",
|
|
38
|
-
import.meta.url
|
|
39
|
-
)
|
|
40
|
-
];
|
|
38
|
+
const possiblePaths = WASM_EMBED_SEARCH_PATHS.map(
|
|
39
|
+
(p) => new URL(p, import.meta.url)
|
|
40
|
+
);
|
|
41
41
|
let wasmData = null;
|
|
42
42
|
let sourcePath = null;
|
|
43
43
|
for (const path of possiblePaths) {
|
|
@@ -68,6 +68,7 @@ async function prepareWasmForEmbedding(outputPath = "./taglib-web.wasm") {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
export {
|
|
71
|
+
WASM_EMBED_SEARCH_PATHS,
|
|
71
72
|
initializeForDenoCompile,
|
|
72
73
|
isDenoCompiled2 as isDenoCompiled,
|
|
73
74
|
prepareWasmForEmbedding
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/msgpack/encoder.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAE/D,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACZ,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/msgpack/encoder.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAE/D,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACZ,MAAM,aAAa,CAAC;AAIrB;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,aAa3B,CAAC;AA4BH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAoC9D;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,6 +1,7 @@
|
|
|
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
|
+
import { isShadowedNumericMirror } from "../utils/mirror-fields.js";
|
|
4
5
|
const PASSTHROUGH_KEYS = /* @__PURE__ */ new Set([
|
|
5
6
|
"pictures",
|
|
6
7
|
"ratings",
|
|
@@ -11,7 +12,9 @@ const PASSTHROUGH_KEYS = /* @__PURE__ */ new Set([
|
|
|
11
12
|
"bextData",
|
|
12
13
|
"ixml",
|
|
13
14
|
"id3Tags",
|
|
14
|
-
"_stripId3"
|
|
15
|
+
"_stripId3",
|
|
16
|
+
// Exact MP4 atom names — must reach C++ verbatim, not via toTagLibKey.
|
|
17
|
+
"_mp4ItemNames"
|
|
15
18
|
]);
|
|
16
19
|
const MSGPACK_ENCODE_OPTIONS = {
|
|
17
20
|
sortKeys: false,
|
|
@@ -29,11 +32,10 @@ function lyricsTexts(value) {
|
|
|
29
32
|
}
|
|
30
33
|
function encodeTagData(tagData) {
|
|
31
34
|
try {
|
|
32
|
-
const
|
|
33
|
-
const hasDate = Array.isArray(dateVal) ? dateVal.length > 0 : dateVal !== void 0 && dateVal !== null && dateVal !== "";
|
|
35
|
+
const data = tagData;
|
|
34
36
|
const remapped = {};
|
|
35
37
|
for (const [key, value] of Object.entries(tagData)) {
|
|
36
|
-
if (key
|
|
38
|
+
if (isShadowedNumericMirror(data, key)) continue;
|
|
37
39
|
if (key === "lyrics") {
|
|
38
40
|
const texts = lyricsTexts(value);
|
|
39
41
|
if (texts.length > 0) remapped["LYRICS"] = texts;
|
|
@@ -23,10 +23,4 @@ export declare function detectRuntime(): RuntimeDetectionResult;
|
|
|
23
23
|
export declare function supportsExnref(): boolean;
|
|
24
24
|
export declare function getEnvironmentDescription(env: RuntimeEnvironment): string;
|
|
25
25
|
export declare function canLoadWasmType(wasmType: WasmBinaryType): boolean;
|
|
26
|
-
/** @internal */
|
|
27
|
-
export declare function _forceRuntime(result: RuntimeDetectionResult): void;
|
|
28
|
-
/** @internal */
|
|
29
|
-
export declare function _clearRuntimeOverride(): void;
|
|
30
|
-
/** @internal */
|
|
31
|
-
export declare function _getDetectionResult(): RuntimeDetectionResult;
|
|
32
26
|
//# sourceMappingURL=detector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../../src/runtime/detector.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,WAAW,GACX,UAAU,GACV,SAAS,GACT,iBAAiB,GACjB,QAAQ,GACR,YAAY,CAAC;AAEjB,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,YAAY,CAAC;AAEnD,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,kBAAkB,CAAC;IAChC,QAAQ,EAAE,cAAc,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,eAAe,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC5B;AAOD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,GAAG,SAAS,CAepB;AAuCD,qFAAqF;AACrF,wBAAgB,MAAM,IAAI,OAAO,CAEhC;AAED,wBAAgB,aAAa,IAAI,sBAAsB,CA8EtD;AAWD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAMxC;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,kBAAkB,GAAG,MAAM,CAmBzE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAQjE
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../../src/runtime/detector.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,WAAW,GACX,UAAU,GACV,SAAS,GACT,iBAAiB,GACjB,QAAQ,GACR,YAAY,CAAC;AAEjB,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,YAAY,CAAC;AAEnD,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,kBAAkB,CAAC;IAChC,QAAQ,EAAE,cAAc,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,eAAe,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC5B;AAOD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,GAAG,SAAS,CAepB;AAuCD,qFAAqF;AACrF,wBAAgB,MAAM,IAAI,OAAO,CAEhC;AAED,wBAAgB,aAAa,IAAI,sBAAsB,CA8EtD;AAWD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAMxC;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,kBAAkB,GAAG,MAAM,CAmBzE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAQjE"}
|
|
@@ -145,7 +145,7 @@ function getEnvironmentDescription(env) {
|
|
|
145
145
|
case "node-wasi":
|
|
146
146
|
return "Node.js with WASI (high performance)";
|
|
147
147
|
case "bun-wasi":
|
|
148
|
-
return "Bun with WASI (
|
|
148
|
+
return "Bun with WASI (Bun-native file I/O)";
|
|
149
149
|
case "browser":
|
|
150
150
|
return "Browser with Emscripten (web compatibility)";
|
|
151
151
|
case "worker":
|
|
@@ -165,20 +165,7 @@ function canLoadWasmType(wasmType) {
|
|
|
165
165
|
}
|
|
166
166
|
return true;
|
|
167
167
|
}
|
|
168
|
-
function _forceRuntime(result) {
|
|
169
|
-
globalThis.__taglib_wasm_runtime_override = result;
|
|
170
|
-
}
|
|
171
|
-
function _clearRuntimeOverride() {
|
|
172
|
-
delete globalThis.__taglib_wasm_runtime_override;
|
|
173
|
-
}
|
|
174
|
-
function _getDetectionResult() {
|
|
175
|
-
const override = globalThis.__taglib_wasm_runtime_override;
|
|
176
|
-
return override || detectRuntime();
|
|
177
|
-
}
|
|
178
168
|
export {
|
|
179
|
-
_clearRuntimeOverride,
|
|
180
|
-
_forceRuntime,
|
|
181
|
-
_getDetectionResult,
|
|
182
169
|
canLoadWasmType,
|
|
183
170
|
checkNodeVersion,
|
|
184
171
|
detectRuntime,
|
|
@@ -30,6 +30,8 @@ export declare class WasiFileHandle implements FileHandle {
|
|
|
30
30
|
isMP4(): boolean;
|
|
31
31
|
getMP4Item(key: string): string;
|
|
32
32
|
setMP4Item(key: string, value: string): void;
|
|
33
|
+
/** Record an exact atom name to be repaired after the PropertyMap write. */
|
|
34
|
+
private registerMp4ItemName;
|
|
33
35
|
removeMP4Item(key: string): void;
|
|
34
36
|
getPictures(): RawPicture[];
|
|
35
37
|
setPictures(pictures: RawPicture[]): void;
|
|
@@ -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,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,SAAS,EACT,UAAU,EACX,MAAM,eAAe,CAAC;AACvB,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;
|
|
1
|
+
{"version":3,"file":"file-handle.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/file-handle.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,SAAS,EACT,UAAU,EACX,MAAM,eAAe,CAAC;AACvB,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;AAyFhE,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;IAgB7C,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;IA6BzC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI;IA6BpD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAShC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAiB7C,KAAK,IAAI,OAAO;IAehB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAK/B,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAS5C,4EAA4E;IAC5E,OAAO,CAAC,mBAAmB;IAU3B,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAahC,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,EAAE,EAAE,OAAO,CAAC;QAAC,EAAE,EAAE,OAAO,CAAA;KAAE;IAQ1C,YAAY,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,EAAE,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IA+BtD,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,SAAS,IAAI,SAAS,EAAE;IAoBxB,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI;IAKpC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,EAAE;IAsB3C,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI;IAUpD,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAInC,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,GAAG,SAAS;IAMhE,OAAO,IAAI,IAAI;CAKhB"}
|
|
@@ -3,7 +3,21 @@ 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
|
import { WasmerExecutionError } from "../wasmer-sdk-loader/types.js";
|
|
5
5
|
import { decodeTagData } from "../../msgpack/decoder.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
fromTagLibKey,
|
|
8
|
+
mp4AtomWireKey,
|
|
9
|
+
toTagLibKey
|
|
10
|
+
} from "../../constants/properties.js";
|
|
11
|
+
import {
|
|
12
|
+
DATE_MIRROR,
|
|
13
|
+
firstValueString,
|
|
14
|
+
isShadowedNumericMirror,
|
|
15
|
+
mirrorForRawKey,
|
|
16
|
+
readNumericMirror,
|
|
17
|
+
stageNumericWrite,
|
|
18
|
+
stageRawWrite,
|
|
19
|
+
TRACK_MIRROR
|
|
20
|
+
} from "../../utils/mirror-fields.js";
|
|
7
21
|
import {
|
|
8
22
|
readId3v2FramesFromWasm,
|
|
9
23
|
readTagsFromWasm,
|
|
@@ -36,7 +50,9 @@ const INTERNAL_KEYS = /* @__PURE__ */ new Set([
|
|
|
36
50
|
"chapters",
|
|
37
51
|
"_mp4ChapterStyle",
|
|
38
52
|
"bextData",
|
|
39
|
-
"ixml"
|
|
53
|
+
"ixml",
|
|
54
|
+
// Exact MP4 atom names for the write path, not a readable property.
|
|
55
|
+
"_mp4ItemNames"
|
|
40
56
|
]);
|
|
41
57
|
const CONTAINER_TO_FORMAT = {
|
|
42
58
|
MP3: "MP3",
|
|
@@ -50,22 +66,11 @@ const CONTAINER_TO_FORMAT = {
|
|
|
50
66
|
ASF: "ASF",
|
|
51
67
|
Matroska: "MATROSKA"
|
|
52
68
|
};
|
|
53
|
-
const NUMERIC_FIELD_ALIASES = {
|
|
54
|
-
trackNumber: "track"
|
|
55
|
-
};
|
|
56
|
-
function hasValue(v) {
|
|
57
|
-
if (Array.isArray(v)) return v.length > 0;
|
|
58
|
-
return v !== void 0 && v !== null && v !== "";
|
|
59
|
-
}
|
|
60
|
-
function firstString(v) {
|
|
61
|
-
if (Array.isArray(v)) return v[0] ?? "";
|
|
62
|
-
return v || "";
|
|
63
|
-
}
|
|
64
69
|
function mp4ItemPropertyKey(key) {
|
|
65
70
|
if (key.startsWith("----:")) {
|
|
66
71
|
return key.slice(key.lastIndexOf(":") + 1).toUpperCase();
|
|
67
72
|
}
|
|
68
|
-
return key;
|
|
73
|
+
return mp4AtomWireKey(key) ?? key;
|
|
69
74
|
}
|
|
70
75
|
class WasiFileHandle {
|
|
71
76
|
constructor(wasiModule) {
|
|
@@ -123,21 +128,23 @@ class WasiFileHandle {
|
|
|
123
128
|
this.checkNotDestroyed();
|
|
124
129
|
const d = this.tagData ?? {};
|
|
125
130
|
return {
|
|
126
|
-
title:
|
|
127
|
-
artist:
|
|
128
|
-
album:
|
|
129
|
-
comment:
|
|
130
|
-
genre:
|
|
131
|
-
year: d
|
|
132
|
-
track: d
|
|
131
|
+
title: firstValueString(d.title),
|
|
132
|
+
artist: firstValueString(d.artist),
|
|
133
|
+
album: firstValueString(d.album),
|
|
134
|
+
comment: firstValueString(d.comment),
|
|
135
|
+
genre: firstValueString(d.genre),
|
|
136
|
+
year: readNumericMirror(d, DATE_MIRROR),
|
|
137
|
+
track: readNumericMirror(d, TRACK_MIRROR)
|
|
133
138
|
};
|
|
134
139
|
}
|
|
135
140
|
setTagData(data) {
|
|
136
141
|
this.checkNotDestroyed();
|
|
137
142
|
const merged = { ...this.tagData, ...data };
|
|
138
143
|
if (data.year !== void 0) {
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
stageNumericWrite(merged, DATE_MIRROR, data.year);
|
|
145
|
+
}
|
|
146
|
+
if (data.track !== void 0) {
|
|
147
|
+
stageNumericWrite(merged, TRACK_MIRROR, data.track);
|
|
141
148
|
}
|
|
142
149
|
this.tagData = merged;
|
|
143
150
|
}
|
|
@@ -211,7 +218,7 @@ class WasiFileHandle {
|
|
|
211
218
|
const data = this.tagData ?? {};
|
|
212
219
|
for (const [key, value] of Object.entries(data)) {
|
|
213
220
|
if (AUDIO_KEYS.has(key) || INTERNAL_KEYS.has(key)) continue;
|
|
214
|
-
if (
|
|
221
|
+
if (isShadowedNumericMirror(data, key)) continue;
|
|
215
222
|
if (value === void 0 || value === null) continue;
|
|
216
223
|
if (value === 0 || value === "") continue;
|
|
217
224
|
const propKey = toTagLibKey(key);
|
|
@@ -230,17 +237,16 @@ class WasiFileHandle {
|
|
|
230
237
|
const next = { ...this.tagData };
|
|
231
238
|
for (const [key, values] of Object.entries(props)) {
|
|
232
239
|
const camelKey = fromTagLibKey(key);
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (!Number.isNaN(year)) next.year = year;
|
|
240
|
+
if (camelKey === "_mp4ItemNames") {
|
|
241
|
+
const existing = next._mp4ItemNames ?? [];
|
|
242
|
+
next._mp4ItemNames = [.../* @__PURE__ */ new Set([...existing, ...values])];
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const mirror = mirrorForRawKey(camelKey);
|
|
246
|
+
if (mirror !== void 0) {
|
|
247
|
+
stageRawWrite(next, mirror, values);
|
|
248
|
+
} else if (values.length === 0) {
|
|
249
|
+
delete next[camelKey];
|
|
244
250
|
} else {
|
|
245
251
|
next[camelKey] = values;
|
|
246
252
|
}
|
|
@@ -250,25 +256,17 @@ class WasiFileHandle {
|
|
|
250
256
|
getProperty(key) {
|
|
251
257
|
this.checkNotDestroyed();
|
|
252
258
|
const mappedKey = fromTagLibKey(key);
|
|
253
|
-
const
|
|
254
|
-
return
|
|
259
|
+
const stored = this.tagData?.[mappedKey];
|
|
260
|
+
return Array.isArray(stored) ? stored[0]?.toString() ?? "" : stored?.toString() ?? "";
|
|
255
261
|
}
|
|
256
262
|
setProperty(key, value) {
|
|
257
263
|
this.checkNotDestroyed();
|
|
258
264
|
const mappedKey = fromTagLibKey(key);
|
|
259
|
-
const
|
|
260
|
-
if (
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
} else if (mappedKey === "date") {
|
|
266
|
-
const year = Number.parseInt(value, 10);
|
|
267
|
-
this.tagData = {
|
|
268
|
-
...this.tagData,
|
|
269
|
-
date: value,
|
|
270
|
-
...Number.isNaN(year) ? {} : { year }
|
|
271
|
-
};
|
|
265
|
+
const mirror = mirrorForRawKey(mappedKey);
|
|
266
|
+
if (mirror !== void 0) {
|
|
267
|
+
const next = { ...this.tagData };
|
|
268
|
+
stageRawWrite(next, mirror, value === "" ? [] : [value]);
|
|
269
|
+
this.tagData = next;
|
|
272
270
|
} else {
|
|
273
271
|
this.tagData = { ...this.tagData, [mappedKey]: value };
|
|
274
272
|
}
|
|
@@ -289,13 +287,24 @@ class WasiFileHandle {
|
|
|
289
287
|
setMP4Item(key, value) {
|
|
290
288
|
this.checkNotDestroyed();
|
|
291
289
|
this.setProperty(mp4ItemPropertyKey(key), value);
|
|
290
|
+
if (key.startsWith("----:")) this.registerMp4ItemName(key);
|
|
291
|
+
}
|
|
292
|
+
/** Record an exact atom name to be repaired after the PropertyMap write. */
|
|
293
|
+
registerMp4ItemName(name) {
|
|
294
|
+
const existing = this.tagData?._mp4ItemNames ?? [];
|
|
295
|
+
if (existing.includes(name)) return;
|
|
296
|
+
this.tagData = {
|
|
297
|
+
...this.tagData,
|
|
298
|
+
_mp4ItemNames: [...existing, name]
|
|
299
|
+
};
|
|
292
300
|
}
|
|
293
301
|
removeMP4Item(key) {
|
|
294
302
|
this.checkNotDestroyed();
|
|
295
303
|
if (this.tagData) {
|
|
296
304
|
const mappedKey = fromTagLibKey(mp4ItemPropertyKey(key));
|
|
297
|
-
|
|
298
|
-
|
|
305
|
+
delete this.tagData[mappedKey];
|
|
306
|
+
const mirror = mirrorForRawKey(mappedKey);
|
|
307
|
+
if (mirror !== void 0) delete this.tagData[mirror.numeric];
|
|
299
308
|
}
|
|
300
309
|
}
|
|
301
310
|
getPictures() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audio-file-base.d.ts","sourceRoot":"","sources":["../../../src/taglib/audio-file-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EACV,eAAe,EACf,QAAQ,EACR,WAAW,EACX,WAAW,EACZ,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"audio-file-base.d.ts","sourceRoot":"","sources":["../../../src/taglib/audio-file-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EACV,eAAe,EACf,QAAQ,EACR,WAAW,EACX,WAAW,EACZ,MAAM,aAAa,CAAC;AAQrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAgBhE;;;;;GAKG;AACH,8BAAsB,iBAAiB;IAWnC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY;IAVzC,SAAS,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IACxC,SAAS,CAAC,qBAAqB,EAAE,eAAe,GAAG,IAAI,CAAQ;IAC/D,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IACvC,SAAS,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,IAAI,CAAC;IACpE,SAAS,CAAC,iBAAiB,EAAE,OAAO,CAAS;IAC7C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC;IACpD,gFAAgF;IAChF,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;gBAGtC,MAAM,EAAE,YAAY,EACvC,UAAU,EAAE,UAAU,EACtB,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;;;;;;OAMG;IACH,SAAS,CAAC,0BAA0B,IAAI,WAAW,CAAC,MAAM,CAAC;IAU3D,SAAS,KAAK,MAAM,IAAI,UAAU,CAKjC;IAED,SAAS,IAAI,QAAQ;IAIrB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,IAAI,cAAc,CAAC,CAAC,CAAC;IAIlE,GAAG,IAAI,UAAU;IAIjB,eAAe,IAAI,eAAe,GAAG,SAAS;IAO9C,UAAU,IAAI,WAAW;IAMzB,aAAa,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI;IAsB5C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAkB5C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAkB7C,KAAK,IAAI,OAAO;IAIhB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAe3C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAoB5C,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAOhC,OAAO,IAAI,OAAO;IAIlB,OAAO,IAAI,IAAI;IAQf,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;CAGzB"}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
mp4AtomWireKey,
|
|
6
|
+
mp4FreeformAtomNames,
|
|
7
|
+
remapKeysFromTagLib,
|
|
8
|
+
toTagLibKey
|
|
9
|
+
} from "../constants/properties.js";
|
|
5
10
|
import { MetadataError, UnsupportedFormatError } from "../errors.js";
|
|
11
|
+
import { MP4_ITEM_NAMES_KEY } from "./mp4-item-names.js";
|
|
12
|
+
import { buildMutableTag } from "./mutable-tag-impl.js";
|
|
6
13
|
const LYRICS_PROPERTY_KEY = "lyrics";
|
|
7
14
|
const LYRICS_WIRE_KEY = toTagLibKey(LYRICS_PROPERTY_KEY);
|
|
8
15
|
const EMPTY_KEY_SET = /* @__PURE__ */ new Set();
|
|
@@ -53,79 +60,7 @@ class BaseAudioFileImpl {
|
|
|
53
60
|
return this.getFormat() === format;
|
|
54
61
|
}
|
|
55
62
|
tag() {
|
|
56
|
-
|
|
57
|
-
let data = handle.getTagData();
|
|
58
|
-
const tag = {
|
|
59
|
-
get title() {
|
|
60
|
-
return data.title;
|
|
61
|
-
},
|
|
62
|
-
get artist() {
|
|
63
|
-
return data.artist;
|
|
64
|
-
},
|
|
65
|
-
get album() {
|
|
66
|
-
return data.album;
|
|
67
|
-
},
|
|
68
|
-
get comment() {
|
|
69
|
-
return data.comment;
|
|
70
|
-
},
|
|
71
|
-
get genre() {
|
|
72
|
-
return data.genre;
|
|
73
|
-
},
|
|
74
|
-
get year() {
|
|
75
|
-
return data.year;
|
|
76
|
-
},
|
|
77
|
-
get track() {
|
|
78
|
-
return data.track;
|
|
79
|
-
},
|
|
80
|
-
get date() {
|
|
81
|
-
return handle.getProperty("DATE") || void 0;
|
|
82
|
-
},
|
|
83
|
-
setTitle: (value) => {
|
|
84
|
-
handle.setTagData({ title: value });
|
|
85
|
-
data = handle.getTagData();
|
|
86
|
-
return tag;
|
|
87
|
-
},
|
|
88
|
-
setArtist: (value) => {
|
|
89
|
-
handle.setTagData({ artist: value });
|
|
90
|
-
data = handle.getTagData();
|
|
91
|
-
return tag;
|
|
92
|
-
},
|
|
93
|
-
setAlbum: (value) => {
|
|
94
|
-
handle.setTagData({ album: value });
|
|
95
|
-
data = handle.getTagData();
|
|
96
|
-
return tag;
|
|
97
|
-
},
|
|
98
|
-
setComment: (value) => {
|
|
99
|
-
handle.setTagData({ comment: value });
|
|
100
|
-
data = handle.getTagData();
|
|
101
|
-
return tag;
|
|
102
|
-
},
|
|
103
|
-
setGenre: (value) => {
|
|
104
|
-
handle.setTagData({ genre: value });
|
|
105
|
-
data = handle.getTagData();
|
|
106
|
-
return tag;
|
|
107
|
-
},
|
|
108
|
-
setYear: (value) => {
|
|
109
|
-
handle.setTagData({ year: value });
|
|
110
|
-
data = handle.getTagData();
|
|
111
|
-
return tag;
|
|
112
|
-
},
|
|
113
|
-
setTrack: (value) => {
|
|
114
|
-
handle.setTagData({ track: value });
|
|
115
|
-
data = handle.getTagData();
|
|
116
|
-
return tag;
|
|
117
|
-
},
|
|
118
|
-
setDate: (value) => {
|
|
119
|
-
if (value === "") {
|
|
120
|
-
handle.setTagData({ year: 0 });
|
|
121
|
-
} else {
|
|
122
|
-
handle.setProperty("DATE", value);
|
|
123
|
-
}
|
|
124
|
-
data = handle.getTagData();
|
|
125
|
-
return tag;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
return tag;
|
|
63
|
+
return buildMutableTag(this.handle);
|
|
129
64
|
}
|
|
130
65
|
audioProperties() {
|
|
131
66
|
if (!this.cachedAudioProperties) {
|
|
@@ -147,14 +82,29 @@ class BaseAudioFileImpl {
|
|
|
147
82
|
const existing = this.handle.getProperties()[LYRICS_WIRE_KEY];
|
|
148
83
|
if (existing !== void 0) translated[LYRICS_WIRE_KEY] = existing;
|
|
149
84
|
}
|
|
85
|
+
const atomNames = mp4FreeformAtomNames(Object.keys(translated));
|
|
86
|
+
if (atomNames.length > 0) translated[MP4_ITEM_NAMES_KEY] = atomNames;
|
|
150
87
|
this.handle.setProperties(translated);
|
|
151
88
|
}
|
|
152
89
|
getProperty(key) {
|
|
153
90
|
const value = this.handle.getProperty(toTagLibKey(key));
|
|
154
|
-
|
|
91
|
+
if (value !== "") return value;
|
|
92
|
+
if (!this.isMP4()) return void 0;
|
|
93
|
+
const remapped = this.properties()[key]?.[0];
|
|
94
|
+
return remapped === "" ? void 0 : remapped;
|
|
155
95
|
}
|
|
156
96
|
setProperty(key, value) {
|
|
157
|
-
|
|
97
|
+
const wireKey = toTagLibKey(key);
|
|
98
|
+
const atomNames = mp4FreeformAtomNames([wireKey]);
|
|
99
|
+
if (atomNames.length > 0 && this.isMP4()) {
|
|
100
|
+
this.handle.setProperties({
|
|
101
|
+
...this.handle.getProperties(),
|
|
102
|
+
[wireKey]: [value],
|
|
103
|
+
[MP4_ITEM_NAMES_KEY]: atomNames
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.handle.setProperty(wireKey, value);
|
|
158
108
|
}
|
|
159
109
|
isMP4() {
|
|
160
110
|
return this.handle.isMP4();
|
|
@@ -163,13 +113,19 @@ class BaseAudioFileImpl {
|
|
|
163
113
|
if (!this.isMP4()) {
|
|
164
114
|
throw new UnsupportedFormatError(this.getFormat(), ["MP4", "M4A"]);
|
|
165
115
|
}
|
|
166
|
-
const
|
|
116
|
+
const wireKey = mp4AtomWireKey(key);
|
|
117
|
+
const value = wireKey !== void 0 ? this.handle.getProperty(wireKey) : this.handle.getMP4Item(key);
|
|
167
118
|
return value === "" ? void 0 : value;
|
|
168
119
|
}
|
|
169
120
|
setMP4Item(key, value) {
|
|
170
121
|
if (!this.isMP4()) {
|
|
171
122
|
throw new UnsupportedFormatError(this.getFormat(), ["MP4", "M4A"]);
|
|
172
123
|
}
|
|
124
|
+
const wireKey = mp4AtomWireKey(key);
|
|
125
|
+
if (wireKey !== void 0) {
|
|
126
|
+
this.handle.setProperty(wireKey, value);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
173
129
|
this.handle.setMP4Item(key, value);
|
|
174
130
|
}
|
|
175
131
|
removeMP4Item(key) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reserved property-map key carrying exact MP4 atom names to the C++ write path.
|
|
3
|
+
*
|
|
4
|
+
* NOT a property and NOT handle state: it is a write-time directive recomputed at
|
|
5
|
+
* each write site from the PROPERTIES table, so it needs no entry in the
|
|
6
|
+
* extra-state reconstruct registry — but every write site that builds a property
|
|
7
|
+
* map must add it, or MP4 freeform atoms get TagLib's upper-cased name
|
|
8
|
+
* (taglib-bnhl). Sites: `BaseAudioFileImpl.setProperties`/`setProperty` and the
|
|
9
|
+
* `saveToFile` reconstruct in `save-reconstruct.ts`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const MP4_ITEM_NAMES_KEY = "_mp4ItemNames";
|
|
12
|
+
//# sourceMappingURL=mp4-item-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mp4-item-names.d.ts","sourceRoot":"","sources":["../../../src/taglib/mp4-item-names.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The mutable `tag()` facade over a FileHandle.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from audio-file-base.ts, which the additions for taglib-qpl/bnhl/eq3
|
|
5
|
+
* pushed past CLAUDE.md's 250-line limit. This is the whole of the basic-tag
|
|
6
|
+
* surface: five plain string fields plus the two that are backed by a raw
|
|
7
|
+
* string with a numeric mirror (`date`/`year`, `trackNumber`/`track`), whose
|
|
8
|
+
* write rules are the interesting part.
|
|
9
|
+
*/
|
|
10
|
+
import type { FileHandle } from "../wasm.js";
|
|
11
|
+
import type { MutableTag } from "./mutable-tag.js";
|
|
12
|
+
/** Build the mutable tag facade. Reads re-snapshot after every write. */
|
|
13
|
+
export declare function buildMutableTag(handle: FileHandle): MutableTag;
|
|
14
|
+
//# sourceMappingURL=mutable-tag-impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutable-tag-impl.d.ts","sourceRoot":"","sources":["../../../src/taglib/mutable-tag-impl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMnD,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CA2F9D"}
|