taglib-wasm 1.5.3 → 1.6.1

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 (52) hide show
  1. package/LICENSE +12 -9
  2. package/README.md +6 -3
  3. package/dist/index.browser.js +402 -90
  4. package/dist/simple.browser.js +400 -89
  5. package/dist/src/constants/complex-properties.d.ts +18 -12
  6. package/dist/src/constants/complex-properties.d.ts.map +1 -1
  7. package/dist/src/constants/properties.d.ts +24 -0
  8. package/dist/src/constants/properties.d.ts.map +1 -1
  9. package/dist/src/constants/properties.js +34 -0
  10. package/dist/src/constants/specialized-properties.d.ts +23 -0
  11. package/dist/src/constants/specialized-properties.d.ts.map +1 -1
  12. package/dist/src/constants/specialized-properties.js +20 -0
  13. package/dist/src/constants/tags.d.ts.map +1 -1
  14. package/dist/src/constants/tags.js +2 -1
  15. package/dist/src/msgpack/encoder.d.ts.map +1 -1
  16. package/dist/src/msgpack/encoder.js +6 -4
  17. package/dist/src/runtime/detector.d.ts +0 -6
  18. package/dist/src/runtime/detector.d.ts.map +1 -1
  19. package/dist/src/runtime/detector.js +1 -14
  20. package/dist/src/runtime/wasi-adapter/file-handle.d.ts +2 -0
  21. package/dist/src/runtime/wasi-adapter/file-handle.d.ts.map +1 -1
  22. package/dist/src/runtime/wasi-adapter/file-handle.js +73 -52
  23. package/dist/src/taglib/audio-file-base.d.ts.map +1 -1
  24. package/dist/src/taglib/audio-file-base.js +33 -77
  25. package/dist/src/taglib/load-audio-data.d.ts.map +1 -1
  26. package/dist/src/taglib/load-audio-data.js +19 -5
  27. package/dist/src/taglib/metadata-extent.d.ts +41 -0
  28. package/dist/src/taglib/metadata-extent.d.ts.map +1 -0
  29. package/dist/src/taglib/metadata-extent.js +128 -0
  30. package/dist/src/taglib/mp4-item-names.d.ts +12 -0
  31. package/dist/src/taglib/mp4-item-names.d.ts.map +1 -0
  32. package/dist/src/taglib/mp4-item-names.js +4 -0
  33. package/dist/src/taglib/mutable-tag-impl.d.ts +14 -0
  34. package/dist/src/taglib/mutable-tag-impl.d.ts.map +1 -0
  35. package/dist/src/taglib/mutable-tag-impl.js +88 -0
  36. package/dist/src/taglib/save-reconstruct.d.ts.map +1 -1
  37. package/dist/src/taglib/save-reconstruct.js +4 -0
  38. package/dist/src/types/metadata-mappings.d.ts.map +1 -1
  39. package/dist/src/types/metadata-mappings.js +14 -0
  40. package/dist/src/types/tags.d.ts +16 -0
  41. package/dist/src/types/tags.d.ts.map +1 -1
  42. package/dist/src/utils/mirror-fields.d.ts +79 -0
  43. package/dist/src/utils/mirror-fields.d.ts.map +1 -0
  44. package/dist/src/utils/mirror-fields.js +67 -0
  45. package/dist/src/utils/tag-mapping.d.ts.map +1 -1
  46. package/dist/src/utils/tag-mapping.js +47 -5
  47. package/dist/src/version.d.ts +1 -1
  48. package/dist/src/version.js +1 -1
  49. package/dist/taglib-wasi.wasm +0 -0
  50. package/dist/taglib-web.wasm +0 -0
  51. package/dist/taglib-wrapper.js +1 -1
  52. package/package.json +3 -3
@@ -3,18 +3,22 @@
3
3
  * These are properties that contain multiple fields and cannot be
4
4
  * represented as simple string values.
5
5
  *
6
+ * These constants describe the shape of each complex property. Values are read
7
+ * and written through dedicated typed accessors, not a generic property call.
8
+ *
6
9
  * @example
7
10
  * ```typescript
8
- * import { COMPLEX_PROPERTIES, COMPLEX_PROPERTY_KEY, Rating } from 'taglib-wasm';
11
+ * import type { Rating } from 'taglib-wasm';
9
12
  *
10
- * // Type-safe property access
11
- * const ratings = file.getComplexProperty(COMPLEX_PROPERTY_KEY.RATING);
13
+ * // Read via the typed accessor
14
+ * const ratings = file.getRatings();
12
15
  * console.log(ratings[0].rating); // 0.0-1.0 normalized
13
16
  *
14
17
  * // Set a rating
15
- * file.setComplexProperty(COMPLEX_PROPERTY_KEY.RATING, [
16
- * { rating: 0.8, email: "user@example.com" }
17
- * ]);
18
+ * file.setRating(0.8, "user@example.com");
19
+ *
20
+ * // Or replace the full list
21
+ * file.setRatings([{ rating: 0.8, email: "user@example.com" }]);
18
22
  * ```
19
23
  */
20
24
  import type { Picture } from "../types.js";
@@ -74,13 +78,15 @@ export interface UnsyncedLyrics {
74
78
  export type VariantMap = Record<string, unknown>;
75
79
  /**
76
80
  * Type map linking complex property keys to their value types.
77
- * Enables type-safe generic methods for getComplexProperty/setComplexProperty.
81
+ *
82
+ * This is a descriptive type map, not the accessor surface — each complex
83
+ * property is reached through its own typed method:
78
84
  *
79
85
  * @example
80
86
  * ```typescript
81
- * // TypeScript knows the return type based on key
82
- * const ratings = file.getComplexProperty("RATING"); // Rating[]
83
- * const pictures = file.getComplexProperty("PICTURE"); // Picture[]
87
+ * const ratings = file.getRatings(); // Rating[]
88
+ * const pictures = file.getPictures(); // Picture[]
89
+ * const chapters = file.getChapters(); // Chapter[]
84
90
  * ```
85
91
  *
86
92
  * Consumers can extend via module augmentation:
@@ -177,8 +183,8 @@ export type ComplexPropertyKeyMap = {
177
183
  *
178
184
  * @example
179
185
  * ```typescript
180
- * // Instead of: file.getComplexProperty(COMPLEX_PROPERTIES.RATING.key)
181
- * file.getComplexProperty(COMPLEX_PROPERTY_KEY.RATING);
186
+ * // Instead of: COMPLEX_PROPERTIES.RATING.key
187
+ * COMPLEX_PROPERTY_KEY.RATING; // "RATING"
182
188
  * ```
183
189
  */
184
190
  export declare const COMPLEX_PROPERTY_KEY: ComplexPropertyKeyMap;
@@ -1 +1 @@
1
- {"version":3,"file":"complex-properties.d.ts","sourceRoot":"","sources":["../../../src/constants/complex-properties.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,WAAW,MAAM;IACrB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,IAAI,EAAE,UAAU,CAAC;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,uBAAuB;IACtC,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,uBAAuB,CAAC;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4CrB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,CAAC,IAAI,kBAAkB,GAAG,CAAC;CACtC,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,qBAKzB,CAAC"}
1
+ {"version":3,"file":"complex-properties.d.ts","sourceRoot":"","sources":["../../../src/constants/complex-properties.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,WAAW,MAAM;IACrB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,IAAI,EAAE,UAAU,CAAC;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,uBAAuB;IACtC,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,uBAAuB,CAAC;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4CrB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,CAAC,IAAI,kBAAkB,GAAG,CAAC;CACtC,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,qBAKzB,CAAC"}
@@ -395,6 +395,20 @@ export declare const PROPERTIES: {
395
395
  readonly mp4: "----:com.apple.iTunes:iTunNORM";
396
396
  };
397
397
  };
398
+ readonly appleGaplessInfo: {
399
+ readonly key: "ITUNSMPB";
400
+ readonly description: "Apple gapless playback data (encoder delay and padding)";
401
+ readonly type: "string";
402
+ readonly supportedFormats: readonly ["ID3v2", "MP4", "Vorbis"];
403
+ readonly mappings: {
404
+ readonly id3v2: {
405
+ readonly frame: "TXXX";
406
+ readonly description: "iTunSMPB";
407
+ };
408
+ readonly vorbis: "ITUNSMPB";
409
+ readonly mp4: "----:com.apple.iTunes:iTunSMPB";
410
+ };
411
+ };
398
412
  readonly albumArtist: {
399
413
  readonly key: "ALBUMARTIST";
400
414
  readonly description: "The album artist (band/orchestra/ensemble)";
@@ -775,6 +789,16 @@ export type PropertyKey = keyof typeof PROPERTIES;
775
789
  export type PropertyValue<K extends PropertyKey> = typeof PROPERTIES[K]["type"] extends "string" ? string : typeof PROPERTIES[K]["type"] extends "number" ? number : typeof PROPERTIES[K]["type"] extends "boolean" ? boolean : string;
776
790
  /** Translate a camelCase property key to TagLib's ALL_CAPS wire key. Unknown keys pass through. */
777
791
  export declare function toTagLibKey(key: string): string;
792
+ /**
793
+ * TagLib wire key for a standard MP4 atom name, or `undefined` for a freeform
794
+ * atom or one we do not model.
795
+ */
796
+ export declare function mp4AtomWireKey(atom: string): string | undefined;
797
+ /**
798
+ * Exact MP4 atom names for the given TagLib wire keys, for keys backed by a
799
+ * mixed-case freeform atom. Empty when none apply, which is the common case.
800
+ */
801
+ export declare function mp4FreeformAtomNames(wireKeys: Iterable<string>): string[];
778
802
  /** Translate a TagLib ALL_CAPS wire key to a camelCase property key. Unknown keys pass through. */
779
803
  export declare function fromTagLibKey(key: string): string;
780
804
  /** Remap all keys of an object from TagLib ALL_CAPS to camelCase. */
@@ -1 +1 @@
1
- {"version":3,"file":"properties.d.ts","sourceRoot":"","sources":["../../../src/constants/properties.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKb,CAAC;AAEX;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,UAAU,CAAC;AAElD;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,WAAW,IAC7C,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,QAAQ,GAAG,MAAM,GAClD,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,QAAQ,GAAG,MAAM,GACtD,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,SAAS,GAAG,OAAO,GACxD,MAAM,CAAC;AAmBb,mGAAmG;AACnG,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GACrB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAMnB;AAGD,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"properties.d.ts","sourceRoot":"","sources":["../../../src/constants/properties.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKb,CAAC;AAEX;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,UAAU,CAAC;AAElD;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,WAAW,IAC7C,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,QAAQ,GAAG,MAAM,GAClD,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,QAAQ,GAAG,MAAM,GACtD,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,SAAS,GAAG,OAAO,GACxD,MAAM,CAAC;AAmBb,mGAAmG;AACnG,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAsDD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAOzE;AAED,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GACrB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAMnB;AAGD,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -21,6 +21,38 @@ _fromTagLib["disc"] = "discNumber";
21
21
  function toTagLibKey(key) {
22
22
  return _toTagLib[key] ?? key;
23
23
  }
24
+ const _mp4FreeformAtoms = {};
25
+ for (const meta of Object.values(PROPERTIES)) {
26
+ const { key, mappings } = meta;
27
+ const atom = mappings?.mp4;
28
+ if (typeof atom !== "string" || !atom.startsWith("----:")) continue;
29
+ const bare = atom.slice(atom.lastIndexOf(":") + 1);
30
+ if (bare === bare.toUpperCase()) continue;
31
+ _mp4FreeformAtoms[key] = atom;
32
+ const readKey = bare.toUpperCase();
33
+ const camel = _fromTagLib[key];
34
+ if (camel !== void 0 && _fromTagLib[readKey] === void 0) {
35
+ _fromTagLib[readKey] = camel;
36
+ }
37
+ }
38
+ const _mp4AtomToWireKey = {};
39
+ for (const meta of Object.values(PROPERTIES)) {
40
+ const { key, mappings } = meta;
41
+ const atom = mappings?.mp4;
42
+ if (typeof atom !== "string" || atom.startsWith("----:")) continue;
43
+ if (_mp4AtomToWireKey[atom] === void 0) _mp4AtomToWireKey[atom] = key;
44
+ }
45
+ function mp4AtomWireKey(atom) {
46
+ return _mp4AtomToWireKey[atom];
47
+ }
48
+ function mp4FreeformAtomNames(wireKeys) {
49
+ const names = [];
50
+ for (const key of wireKeys) {
51
+ const atom = _mp4FreeformAtoms[key];
52
+ if (atom !== void 0) names.push(atom);
53
+ }
54
+ return names;
55
+ }
24
56
  function fromTagLibKey(key) {
25
57
  return _fromTagLib[key] ?? key;
26
58
  }
@@ -34,6 +66,8 @@ function remapKeysFromTagLib(obj) {
34
66
  export {
35
67
  PROPERTIES,
36
68
  fromTagLibKey,
69
+ mp4AtomWireKey,
70
+ mp4FreeformAtomNames,
37
71
  remapKeysFromTagLib,
38
72
  toTagLibKey
39
73
  };
@@ -157,5 +157,28 @@ export declare const SPECIALIZED_PROPERTIES: {
157
157
  readonly mp4: "----:com.apple.iTunes:iTunNORM";
158
158
  };
159
159
  };
160
+ /**
161
+ * Apple gapless-playback data (encoder delay, padding, original sample count).
162
+ *
163
+ * Exists so the two Apple freeform atoms are presented consistently: without
164
+ * it, `properties()` answered `appleSoundCheck` for iTunNORM but the raw
165
+ * uppercased `ITUNSMPB` for its sibling, because only one had an alias. The
166
+ * name mirrors `appleSoundCheck` — vendor-prefixed, feature-named rather than
167
+ * atom-named (tuneup-ibo).
168
+ */
169
+ readonly appleGaplessInfo: {
170
+ readonly key: "ITUNSMPB";
171
+ readonly description: "Apple gapless playback data (encoder delay and padding)";
172
+ readonly type: "string";
173
+ readonly supportedFormats: readonly ["ID3v2", "MP4", "Vorbis"];
174
+ readonly mappings: {
175
+ readonly id3v2: {
176
+ readonly frame: "TXXX";
177
+ readonly description: "iTunSMPB";
178
+ };
179
+ readonly vorbis: "ITUNSMPB";
180
+ readonly mp4: "----:com.apple.iTunes:iTunSMPB";
181
+ };
182
+ };
160
183
  };
161
184
  //# sourceMappingURL=specialized-properties.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"specialized-properties.d.ts","sourceRoot":"","sources":["../../../src/constants/specialized-properties.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiIzB,CAAC"}
1
+ {"version":3,"file":"specialized-properties.d.ts","sourceRoot":"","sources":["../../../src/constants/specialized-properties.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAiIjC;;;;;;;;OAQG;;;;;;;;;;;;;;;CAYK,CAAC"}
@@ -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;AAErD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,OAAO,CAE5D;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,SAAS,OAAO,EAAE,CAEnD"}
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 Object.values(Tags).includes(name);
77
+ return VALID_TAG_NAMES.has(name);
77
78
  }
78
79
  function getAllTagNames() {
79
80
  return Object.values(Tags);
@@ -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;AAGrB;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,aAW3B,CAAC;AA4BH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,CAsC9D;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,eAAe,GAAG,UAAU,CAS7E;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAStE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAe1D;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,UAAU,CAelE;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,IAAI,EAAE,CAAC,EACP,OAAO,GAAE,OAAO,CAAC,cAAc,CAAM,GACpC,UAAU,CAUZ;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,UAAU,CAe/D;AAqBD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,UAAU,CAc1E;AAED,wBAAiB,uBAAuB,CAAC,CAAC,EACxC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,GACxB,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CActC;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAS7D;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,GAC1E,UAAU,CAeZ;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAW7D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG;IACxD,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAaA"}
1
+ {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/msgpack/encoder.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAE/D,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,OAAO,EACP,WAAW,EACZ,MAAM,aAAa,CAAC;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 dateVal = tagData.date;
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 === "year" && hasDate) continue;
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;AAED,gBAAgB;AAChB,wBAAgB,aAAa,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAElE;AAED,gBAAgB;AAChB,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,gBAAgB;AAChB,wBAAgB,mBAAmB,IAAI,sBAAsB,CAG5D"}
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 (via node:fs)";
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":"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"}
1
+ {"version":3,"file":"file-handle.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/file-handle.ts"],"names":[],"mappings":"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"}
@@ -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 { fromTagLibKey, toTagLibKey } from "../../constants/properties.js";
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: firstString(d.title),
127
- artist: firstString(d.artist),
128
- album: firstString(d.album),
129
- comment: firstString(d.comment),
130
- genre: firstString(d.genre),
131
- year: d.year || 0,
132
- track: d.track || 0
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
- if (data.year > 0) merged.date = String(data.year);
140
- else delete merged.date;
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,8 @@ 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 (key === "year" && hasValue(data.date)) continue;
221
+ if (key.startsWith("----:")) continue;
222
+ if (isShadowedNumericMirror(data, key)) continue;
215
223
  if (value === void 0 || value === null) continue;
216
224
  if (value === 0 || value === "") continue;
217
225
  const propKey = toTagLibKey(key);
@@ -230,17 +238,16 @@ class WasiFileHandle {
230
238
  const next = { ...this.tagData };
231
239
  for (const [key, values] of Object.entries(props)) {
232
240
  const camelKey = fromTagLibKey(key);
233
- const storeKey = NUMERIC_FIELD_ALIASES[camelKey] ?? camelKey;
234
- if (values.length === 0) {
235
- delete next[storeKey];
236
- if (camelKey === "date") delete next.year;
237
- } else if (storeKey === "track") {
238
- const parsed = Number.parseInt(values[0] ?? "", 10);
239
- if (!Number.isNaN(parsed)) next[storeKey] = parsed;
240
- } else if (camelKey === "date") {
241
- next.date = values;
242
- const year = Number.parseInt(values[0] ?? "", 10);
243
- if (!Number.isNaN(year)) next.year = year;
241
+ if (camelKey === "_mp4ItemNames") {
242
+ const existing = next._mp4ItemNames ?? [];
243
+ next._mp4ItemNames = [.../* @__PURE__ */ new Set([...existing, ...values])];
244
+ continue;
245
+ }
246
+ const mirror = mirrorForRawKey(camelKey);
247
+ if (mirror !== void 0) {
248
+ stageRawWrite(next, mirror, values);
249
+ } else if (values.length === 0) {
250
+ delete next[camelKey];
244
251
  } else {
245
252
  next[camelKey] = values;
246
253
  }
@@ -250,25 +257,17 @@ class WasiFileHandle {
250
257
  getProperty(key) {
251
258
  this.checkNotDestroyed();
252
259
  const mappedKey = fromTagLibKey(key);
253
- const storeKey = NUMERIC_FIELD_ALIASES[mappedKey] ?? mappedKey;
254
- return this.tagData?.[storeKey]?.toString() ?? "";
260
+ const stored = this.tagData?.[mappedKey];
261
+ return Array.isArray(stored) ? stored[0]?.toString() ?? "" : stored?.toString() ?? "";
255
262
  }
256
263
  setProperty(key, value) {
257
264
  this.checkNotDestroyed();
258
265
  const mappedKey = fromTagLibKey(key);
259
- const storeKey = NUMERIC_FIELD_ALIASES[mappedKey] ?? mappedKey;
260
- if (storeKey === "track") {
261
- const parsed = Number.parseInt(value, 10);
262
- if (!Number.isNaN(parsed)) {
263
- this.tagData = { ...this.tagData, [storeKey]: parsed };
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
- };
266
+ const mirror = mirrorForRawKey(mappedKey);
267
+ if (mirror !== void 0) {
268
+ const next = { ...this.tagData };
269
+ stageRawWrite(next, mirror, value === "" ? [] : [value]);
270
+ this.tagData = next;
272
271
  } else {
273
272
  this.tagData = { ...this.tagData, [mappedKey]: value };
274
273
  }
@@ -284,18 +283,40 @@ class WasiFileHandle {
284
283
  }
285
284
  getMP4Item(key) {
286
285
  this.checkNotDestroyed();
286
+ if (key.startsWith("----:")) {
287
+ const foreign = this.tagData?.[key];
288
+ if (foreign !== void 0) {
289
+ return Array.isArray(foreign) ? foreign[0]?.toString() ?? "" : String(foreign);
290
+ }
291
+ }
287
292
  return this.getProperty(mp4ItemPropertyKey(key));
288
293
  }
289
294
  setMP4Item(key, value) {
290
295
  this.checkNotDestroyed();
291
296
  this.setProperty(mp4ItemPropertyKey(key), value);
297
+ if (key.startsWith("----:")) {
298
+ this.registerMp4ItemName(key);
299
+ if (this.tagData?.[key] !== void 0) {
300
+ this.tagData = { ...this.tagData, [key]: value };
301
+ }
302
+ }
303
+ }
304
+ /** Record an exact atom name to be repaired after the PropertyMap write. */
305
+ registerMp4ItemName(name) {
306
+ const existing = this.tagData?._mp4ItemNames ?? [];
307
+ if (existing.includes(name)) return;
308
+ this.tagData = {
309
+ ...this.tagData,
310
+ _mp4ItemNames: [...existing, name]
311
+ };
292
312
  }
293
313
  removeMP4Item(key) {
294
314
  this.checkNotDestroyed();
295
315
  if (this.tagData) {
296
316
  const mappedKey = fromTagLibKey(mp4ItemPropertyKey(key));
297
- const storeKey = NUMERIC_FIELD_ALIASES[mappedKey] ?? mappedKey;
298
- delete this.tagData[storeKey];
317
+ delete this.tagData[mappedKey];
318
+ const mirror = mirrorForRawKey(mappedKey);
319
+ if (mirror !== void 0) delete this.tagData[mirror.numeric];
299
320
  }
300
321
  }
301
322
  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;AAGrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAchE;;;;;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;IA4EjB,eAAe,IAAI,eAAe,GAAG,SAAS;IAO9C,UAAU,IAAI,WAAW;IAMzB,aAAa,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI;IAiB5C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK5C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7C,KAAK,IAAI,OAAO;IAIhB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAQ3C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAO5C,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
+ {"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"}