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
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { toTagLibKey } from "../constants/properties.js";
|
|
2
|
+
const RAW_TRACK_WIRE_KEY = toTagLibKey("trackNumber");
|
|
3
|
+
function buildMutableTag(handle) {
|
|
4
|
+
let data = handle.getTagData();
|
|
5
|
+
const tag = {
|
|
6
|
+
get title() {
|
|
7
|
+
return data.title;
|
|
8
|
+
},
|
|
9
|
+
get artist() {
|
|
10
|
+
return data.artist;
|
|
11
|
+
},
|
|
12
|
+
get album() {
|
|
13
|
+
return data.album;
|
|
14
|
+
},
|
|
15
|
+
get comment() {
|
|
16
|
+
return data.comment;
|
|
17
|
+
},
|
|
18
|
+
get genre() {
|
|
19
|
+
return data.genre;
|
|
20
|
+
},
|
|
21
|
+
get year() {
|
|
22
|
+
return data.year;
|
|
23
|
+
},
|
|
24
|
+
get track() {
|
|
25
|
+
return data.track;
|
|
26
|
+
},
|
|
27
|
+
get date() {
|
|
28
|
+
return handle.getProperty("DATE") || void 0;
|
|
29
|
+
},
|
|
30
|
+
setTitle: (value) => {
|
|
31
|
+
handle.setTagData({ title: value });
|
|
32
|
+
data = handle.getTagData();
|
|
33
|
+
return tag;
|
|
34
|
+
},
|
|
35
|
+
setArtist: (value) => {
|
|
36
|
+
handle.setTagData({ artist: value });
|
|
37
|
+
data = handle.getTagData();
|
|
38
|
+
return tag;
|
|
39
|
+
},
|
|
40
|
+
setAlbum: (value) => {
|
|
41
|
+
handle.setTagData({ album: value });
|
|
42
|
+
data = handle.getTagData();
|
|
43
|
+
return tag;
|
|
44
|
+
},
|
|
45
|
+
setComment: (value) => {
|
|
46
|
+
handle.setTagData({ comment: value });
|
|
47
|
+
data = handle.getTagData();
|
|
48
|
+
return tag;
|
|
49
|
+
},
|
|
50
|
+
setGenre: (value) => {
|
|
51
|
+
handle.setTagData({ genre: value });
|
|
52
|
+
data = handle.getTagData();
|
|
53
|
+
return tag;
|
|
54
|
+
},
|
|
55
|
+
setYear: (value) => {
|
|
56
|
+
handle.setTagData({ year: value });
|
|
57
|
+
data = handle.getTagData();
|
|
58
|
+
return tag;
|
|
59
|
+
},
|
|
60
|
+
setTrack: (value) => {
|
|
61
|
+
const existing = value > 0 ? handle.getProperty(RAW_TRACK_WIRE_KEY) : "";
|
|
62
|
+
const slash = existing.indexOf("/");
|
|
63
|
+
if (slash !== -1) {
|
|
64
|
+
handle.setProperty(
|
|
65
|
+
RAW_TRACK_WIRE_KEY,
|
|
66
|
+
`${value}${existing.slice(slash)}`
|
|
67
|
+
);
|
|
68
|
+
} else {
|
|
69
|
+
handle.setTagData({ track: value });
|
|
70
|
+
}
|
|
71
|
+
data = handle.getTagData();
|
|
72
|
+
return tag;
|
|
73
|
+
},
|
|
74
|
+
setDate: (value) => {
|
|
75
|
+
if (value === "") {
|
|
76
|
+
handle.setTagData({ year: 0 });
|
|
77
|
+
} else {
|
|
78
|
+
handle.setProperty("DATE", value);
|
|
79
|
+
}
|
|
80
|
+
data = handle.getTagData();
|
|
81
|
+
return tag;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return tag;
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
buildMutableTag
|
|
88
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save-reconstruct.d.ts","sourceRoot":"","sources":["../../../src/taglib/save-reconstruct.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"save-reconstruct.d.ts","sourceRoot":"","sources":["../../../src/taglib/save-reconstruct.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA6C3D;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,IAAI,EAChD,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,OAAO,EACvB,WAAW,GAAE,WAAW,CAAC,MAAM,CAAa,GAC3C,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
|
|
@@ -3,10 +3,14 @@ import { readFileData } from "../utils/file.js";
|
|
|
3
3
|
import { writeFileData } from "../utils/write.js";
|
|
4
4
|
import { wrapEmbindHandle } from "./embind-adapter.js";
|
|
5
5
|
import { copyExtraState } from "./extra-state-registry.js";
|
|
6
|
+
import { mp4FreeformAtomNames } from "../constants/properties.js";
|
|
7
|
+
import { MP4_ITEM_NAMES_KEY } from "./mp4-item-names.js";
|
|
6
8
|
function copyEditedState(target, source, sourceComplete, deletedKeys) {
|
|
7
9
|
target.setTagData(source.getTagData());
|
|
8
10
|
const merged = sourceComplete ? source.getProperties() : { ...target.getProperties(), ...source.getProperties() };
|
|
9
11
|
for (const key of deletedKeys) delete merged[key];
|
|
12
|
+
const atomNames = mp4FreeformAtomNames(Object.keys(merged));
|
|
13
|
+
if (atomNames.length > 0) merged[MP4_ITEM_NAMES_KEY] = atomNames;
|
|
10
14
|
target.setProperties(merged);
|
|
11
15
|
copyExtraState(target, source, sourceComplete);
|
|
12
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata-mappings.d.ts","sourceRoot":"","sources":["../../../src/types/metadata-mappings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CACpC,OAAO,CACL,MAAM,WAAW,EACf,UAAU,GACV,SAAS,GACT,QAAQ,GACR,UAAU,GACV,MAAM,GACN,UAAU,GACV,MAAM,GACN,aAAa,CAChB,EACD,YAAY,
|
|
1
|
+
{"version":3,"file":"metadata-mappings.d.ts","sourceRoot":"","sources":["../../../src/types/metadata-mappings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CACpC,OAAO,CACL,MAAM,WAAW,EACf,UAAU,GACV,SAAS,GACT,QAAQ,GACR,UAAU,GACV,MAAM,GACN,UAAU,GACV,MAAM,GACN,aAAa,CAChB,EACD,YAAY,CA8Nb,CAAC"}
|
|
@@ -50,6 +50,14 @@ const METADATA_MAPPINGS = {
|
|
|
50
50
|
mp4: "trkn",
|
|
51
51
|
wav: "ITRK"
|
|
52
52
|
},
|
|
53
|
+
// Raw track string — same underlying frames as `track`, but preserves
|
|
54
|
+
// zero-padding and the "/total" suffix instead of collapsing to an integer.
|
|
55
|
+
trackNumber: {
|
|
56
|
+
id3v2: { frame: "TRCK" },
|
|
57
|
+
vorbis: "TRACKNUMBER",
|
|
58
|
+
mp4: "trkn",
|
|
59
|
+
wav: "ITRK"
|
|
60
|
+
},
|
|
53
61
|
// Advanced fields requiring format-specific handling
|
|
54
62
|
acoustidFingerprint: {
|
|
55
63
|
id3v2: { frame: "TXXX", description: "Acoustid Fingerprint" },
|
|
@@ -206,6 +214,12 @@ const METADATA_MAPPINGS = {
|
|
|
206
214
|
vorbis: "ITUNNORM",
|
|
207
215
|
// Some tools store it in Vorbis comments too
|
|
208
216
|
mp4: "----:com.apple.iTunes:iTunNORM"
|
|
217
|
+
},
|
|
218
|
+
// Same underlying frames pattern as appleSoundCheck, for the sibling atom.
|
|
219
|
+
appleGaplessInfo: {
|
|
220
|
+
id3v2: { frame: "TXXX", description: "iTunSMPB" },
|
|
221
|
+
vorbis: "ITUNSMPB",
|
|
222
|
+
mp4: "----:com.apple.iTunes:iTunSMPB"
|
|
209
223
|
}
|
|
210
224
|
};
|
|
211
225
|
export {
|
package/dist/src/types/tags.d.ts
CHANGED
|
@@ -77,7 +77,14 @@ export interface TagInput {
|
|
|
77
77
|
readonly date?: string | string[];
|
|
78
78
|
/** Track number */
|
|
79
79
|
readonly track?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Raw track field (e.g. "03" or "3/12"). Maps to the same TRACKNUMBER tag as
|
|
82
|
+
* {@link track}; when both are provided, `trackNumber` wins (it preserves
|
|
83
|
+
* zero-padding and the "/total" suffix that a number cannot).
|
|
84
|
+
*/
|
|
85
|
+
readonly trackNumber?: string | string[];
|
|
80
86
|
readonly appleSoundCheck?: string | string[];
|
|
87
|
+
readonly appleGaplessInfo?: string | string[];
|
|
81
88
|
readonly albumArtist?: string | string[];
|
|
82
89
|
readonly composer?: string | string[];
|
|
83
90
|
readonly conductor?: string | string[];
|
|
@@ -135,6 +142,13 @@ export interface ExtendedTag extends Tag {
|
|
|
135
142
|
* Preserves day/month precision that the numeric {@link Tag.year} cannot.
|
|
136
143
|
*/
|
|
137
144
|
readonly date?: string | string[];
|
|
145
|
+
/**
|
|
146
|
+
* Raw track field as stored in TRACKNUMBER (e.g. "03" or "3/12"). Preserves
|
|
147
|
+
* the zero-padding and the "/total" suffix that the numeric
|
|
148
|
+
* {@link Tag.track} cannot, so a readTags() -> applyTags() round-trip does
|
|
149
|
+
* not silently drop them (taglib-qpl).
|
|
150
|
+
*/
|
|
151
|
+
readonly trackNumber?: string | string[];
|
|
138
152
|
/** AcoustID fingerprint (Chromaprint) */
|
|
139
153
|
readonly acoustidFingerprint?: string[];
|
|
140
154
|
/** AcoustID UUID */
|
|
@@ -203,6 +217,8 @@ export interface ExtendedTag extends Tag {
|
|
|
203
217
|
readonly replayGainAlbumPeak?: string[];
|
|
204
218
|
/** Apple Sound Check normalization data (iTunNORM) */
|
|
205
219
|
readonly appleSoundCheck?: string[];
|
|
220
|
+
/** Apple gapless playback data: encoder delay and padding (iTunSMPB) */
|
|
221
|
+
readonly appleGaplessInfo?: string[];
|
|
206
222
|
/** Embedded pictures/artwork */
|
|
207
223
|
readonly pictures?: import("./pictures.js").Picture[];
|
|
208
224
|
/** Popularity/rating data. Same shape as {@link AudioFile.getRatings}. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../../src/types/tags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,GAAG;IAClB,kBAAkB;IAClB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB;IAClB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,iBAAiB;IACjB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc;IACd,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY;IACZ,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW;IACX,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB;IACnB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,QAAQ;IACvB,kBAAkB;IAClB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACnC,kBAAkB;IAClB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,iBAAiB;IACjB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACnC,cAAc;IACd,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACrC,YAAY;IACZ,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACnC,WAAW;IACX,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAClC,mBAAmB;IACnB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../../src/types/tags.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Raw-string / numeric-mirror field pairs.
|
|
3
|
+
*
|
|
4
|
+
* Two tag fields are stored twice: a RAW string that is authoritative and can
|
|
5
|
+
* hold what a number cannot ("1975-10-31", "3/12", "03"), and a narrowed numeric
|
|
6
|
+
* MIRROR that the typed `tag()` surface promises (`year`, `track`). Both map to
|
|
7
|
+
* the same TagLib wire key, so exactly one of them may cross the boundary.
|
|
8
|
+
*
|
|
9
|
+
* The rules are few but easy to get subtly wrong, and they were previously
|
|
10
|
+
* hand-written at seven sites across two files. The copies drifted, and the
|
|
11
|
+
* drift was not cosmetic — every bug below came from one site knowing a rule its
|
|
12
|
+
* twin did not:
|
|
13
|
+
*
|
|
14
|
+
* - taglib-qpl: `setProperty` left a stale mirror when the new raw value did
|
|
15
|
+
* not parse, so `tag().track` reported the previous number.
|
|
16
|
+
* - taglib-qpl: `setProperty("")` did not clear, so a deletion was a silent
|
|
17
|
+
* no-op and the old number was written back to disk.
|
|
18
|
+
* - taglib-iyfr: both of the above were still live for `date`/`year`, because
|
|
19
|
+
* only the `trackNumber`/`track` copy had been fixed.
|
|
20
|
+
*
|
|
21
|
+
* So the rules live here once, and adding a third pair is a one-line change.
|
|
22
|
+
*/
|
|
23
|
+
/** A raw-string field and the numeric mirror derived from it. */
|
|
24
|
+
export type MirrorField = {
|
|
25
|
+
/** camelCase key holding the raw string. Authoritative. */
|
|
26
|
+
readonly raw: string;
|
|
27
|
+
/** camelCase key holding the narrowed number. Derived, never authoritative. */
|
|
28
|
+
readonly numeric: string;
|
|
29
|
+
};
|
|
30
|
+
export declare const MIRROR_FIELDS: readonly MirrorField[];
|
|
31
|
+
/**
|
|
32
|
+
* Leading integer of a raw field value, or `undefined` when it does not parse.
|
|
33
|
+
* The single definition of the narrowing convention: `parseInt` semantics, so
|
|
34
|
+
* "3/12" is 3 and "03" is 3, and a non-numeric value has no mirror at all.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseLeadingInt(raw: string): number | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* The two pairs by name. Exported so callers need no unchecked cast over a
|
|
39
|
+
* lookup that can return undefined — renaming a field in MIRROR_FIELDS then
|
|
40
|
+
* fails at build time here instead of throwing at the first read.
|
|
41
|
+
*/
|
|
42
|
+
export declare const DATE_MIRROR: MirrorField;
|
|
43
|
+
export declare const TRACK_MIRROR: MirrorField;
|
|
44
|
+
/** The pair whose raw key is `key`, if any. */
|
|
45
|
+
export declare function mirrorForRawKey(key: string): MirrorField | undefined;
|
|
46
|
+
/** The pair whose numeric key is `key`, if any. */
|
|
47
|
+
export declare function mirrorForNumericKey(key: string): MirrorField | undefined;
|
|
48
|
+
/** First element of an array value, or the scalar itself, as a string. */
|
|
49
|
+
export declare function firstValueString(v: unknown): string;
|
|
50
|
+
/**
|
|
51
|
+
* True when `key` is a numeric mirror whose raw partner currently holds a value.
|
|
52
|
+
*
|
|
53
|
+
* Both keys translate to one wire key, so emitting both would collide — the raw
|
|
54
|
+
* string wins because it carries strictly more information. Used by the WASI
|
|
55
|
+
* property snapshot and by the msgpack encoder, which previously each inlined
|
|
56
|
+
* their own copy of this test.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isShadowedNumericMirror(data: Record<string, unknown>, key: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Stage a RAW write: store the string and re-derive the mirror. An empty value
|
|
61
|
+
* list clears the field, which is what lets `clearTags()` remove it under WASI's
|
|
62
|
+
* merge model; an unparseable value drops the mirror rather than leaving a stale
|
|
63
|
+
* number behind. Mutates `target`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function stageRawWrite(target: Record<string, unknown>, field: MirrorField, values: readonly string[]): void;
|
|
66
|
+
/**
|
|
67
|
+
* Stage a NUMERIC write from the typed `tag()` surface: the number is
|
|
68
|
+
* authoritative, so the raw mirror is replaced rather than merged — a stale
|
|
69
|
+
* "3/12" must not shadow a newly set 7. A non-positive value is a clear, not a
|
|
70
|
+
* renumbering. Mutates `target`.
|
|
71
|
+
*/
|
|
72
|
+
export declare function stageNumericWrite(target: Record<string, unknown>, field: MirrorField, value: number): void;
|
|
73
|
+
/**
|
|
74
|
+
* Numeric value for the typed surface: the mirror when present, otherwise
|
|
75
|
+
* narrowed from the raw string so a handle that only ever saw the raw value
|
|
76
|
+
* still reports a number.
|
|
77
|
+
*/
|
|
78
|
+
export declare function readNumericMirror(data: Record<string, unknown>, field: MirrorField): number;
|
|
79
|
+
//# sourceMappingURL=mirror-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mirror-fields.d.ts","sourceRoot":"","sources":["../../../src/utils/mirror-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,iEAAiE;AACjE,MAAM,MAAM,WAAW,GAAG;IACxB,2DAA2D;IAC3D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAG/C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG/D;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,WAA+B,CAAC;AAC1D,eAAO,MAAM,YAAY,EAAE,WAA+B,CAAC;AAE3D,+CAA+C;AAC/C,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEpE;AAED,mDAAmD;AACnD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAExE;AAQD,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAGnD;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,MAAM,GACV,OAAO,CAGT;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,IAAI,CAWN;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,GACZ,IAAI,CAQN;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,WAAW,GACjB,MAAM,CAIR"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const MIRROR_FIELDS = [
|
|
2
|
+
{ raw: "date", numeric: "year" },
|
|
3
|
+
{ raw: "trackNumber", numeric: "track" }
|
|
4
|
+
];
|
|
5
|
+
function parseLeadingInt(raw) {
|
|
6
|
+
const parsed = Number.parseInt(raw, 10);
|
|
7
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
8
|
+
}
|
|
9
|
+
const DATE_MIRROR = MIRROR_FIELDS[0];
|
|
10
|
+
const TRACK_MIRROR = MIRROR_FIELDS[1];
|
|
11
|
+
function mirrorForRawKey(key) {
|
|
12
|
+
return MIRROR_FIELDS.find((f) => f.raw === key);
|
|
13
|
+
}
|
|
14
|
+
function mirrorForNumericKey(key) {
|
|
15
|
+
return MIRROR_FIELDS.find((f) => f.numeric === key);
|
|
16
|
+
}
|
|
17
|
+
function hasValue(v) {
|
|
18
|
+
if (Array.isArray(v)) return v.length > 0;
|
|
19
|
+
return v !== void 0 && v !== null && v !== "";
|
|
20
|
+
}
|
|
21
|
+
function firstValueString(v) {
|
|
22
|
+
if (Array.isArray(v)) return v[0] ?? "";
|
|
23
|
+
return v === void 0 || v === null ? "" : String(v);
|
|
24
|
+
}
|
|
25
|
+
function isShadowedNumericMirror(data, key) {
|
|
26
|
+
const field = mirrorForNumericKey(key);
|
|
27
|
+
return field !== void 0 && hasValue(data[field.raw]);
|
|
28
|
+
}
|
|
29
|
+
function stageRawWrite(target, field, values) {
|
|
30
|
+
const first = values[0] ?? "";
|
|
31
|
+
if (values.length === 0 || first === "") {
|
|
32
|
+
delete target[field.raw];
|
|
33
|
+
delete target[field.numeric];
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
target[field.raw] = [...values];
|
|
37
|
+
const narrowed = parseLeadingInt(first);
|
|
38
|
+
if (narrowed === void 0) delete target[field.numeric];
|
|
39
|
+
else target[field.numeric] = narrowed;
|
|
40
|
+
}
|
|
41
|
+
function stageNumericWrite(target, field, value) {
|
|
42
|
+
if (value > 0) {
|
|
43
|
+
target[field.numeric] = value;
|
|
44
|
+
target[field.raw] = [String(value)];
|
|
45
|
+
} else {
|
|
46
|
+
delete target[field.numeric];
|
|
47
|
+
delete target[field.raw];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function readNumericMirror(data, field) {
|
|
51
|
+
const mirror = data[field.numeric];
|
|
52
|
+
if (typeof mirror === "number" && mirror !== 0) return mirror;
|
|
53
|
+
return parseLeadingInt(firstValueString(data[field.raw])) ?? 0;
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
DATE_MIRROR,
|
|
57
|
+
MIRROR_FIELDS,
|
|
58
|
+
TRACK_MIRROR,
|
|
59
|
+
firstValueString,
|
|
60
|
+
isShadowedNumericMirror,
|
|
61
|
+
mirrorForNumericKey,
|
|
62
|
+
mirrorForRawKey,
|
|
63
|
+
parseLeadingInt,
|
|
64
|
+
readNumericMirror,
|
|
65
|
+
stageNumericWrite,
|
|
66
|
+
stageRawWrite
|
|
67
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-mapping.d.ts","sourceRoot":"","sources":["../../../src/utils/tag-mapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"tag-mapping.d.ts","sourceRoot":"","sources":["../../../src/utils/tag-mapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAqCtE;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,WAAW,CAuBjE;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CA8D1E;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,GACtB,IAAI,CAKN;AAoDD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,GACvB,WAAW,CA+Db"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fromTagLibKey } from "../constants/properties.js";
|
|
2
|
+
import { parseLeadingInt as parseNumeric } from "./mirror-fields.js";
|
|
2
3
|
const BASIC_PROPERTY_KEYS = {
|
|
3
4
|
title: "title",
|
|
4
5
|
artist: "artist",
|
|
@@ -16,7 +17,8 @@ const BASIC_FIELDS = /* @__PURE__ */ new Set([
|
|
|
16
17
|
"genre",
|
|
17
18
|
"year",
|
|
18
19
|
"date",
|
|
19
|
-
"track"
|
|
20
|
+
"track",
|
|
21
|
+
"trackNumber"
|
|
20
22
|
]);
|
|
21
23
|
const NUMERIC_FIELDS = /* @__PURE__ */ new Set([
|
|
22
24
|
"year",
|
|
@@ -26,10 +28,6 @@ const NUMERIC_FIELDS = /* @__PURE__ */ new Set([
|
|
|
26
28
|
"totalDiscs",
|
|
27
29
|
"bpm"
|
|
28
30
|
]);
|
|
29
|
-
function parseNumeric(value) {
|
|
30
|
-
const parsed = Number.parseInt(value, 10);
|
|
31
|
-
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
32
|
-
}
|
|
33
31
|
function readExtendedTag(audioFile) {
|
|
34
32
|
const tag = mapPropertiesToExtendedTag(audioFile.properties());
|
|
35
33
|
const pictures = audioFile.getPictures();
|
|
@@ -59,10 +57,24 @@ function mapPropertiesToExtendedTag(props) {
|
|
|
59
57
|
if (propKey === "date") {
|
|
60
58
|
tag.date = values.length === 1 ? values[0] : values;
|
|
61
59
|
}
|
|
60
|
+
if (propKey === "trackNumber") {
|
|
61
|
+
tag.trackNumber = values.length === 1 ? values[0] : values;
|
|
62
|
+
}
|
|
62
63
|
} else {
|
|
63
64
|
tag[tagField] = values;
|
|
64
65
|
}
|
|
65
66
|
}
|
|
67
|
+
for (const [propKey, totalField] of [
|
|
68
|
+
["trackNumber", "totalTracks"],
|
|
69
|
+
["discNumber", "totalDiscs"]
|
|
70
|
+
]) {
|
|
71
|
+
if (tag[totalField] !== void 0) continue;
|
|
72
|
+
const raw = props[propKey]?.[0];
|
|
73
|
+
const slash = raw?.indexOf("/") ?? -1;
|
|
74
|
+
if (raw === void 0 || slash === -1) continue;
|
|
75
|
+
const total = parseNumeric(raw.slice(slash + 1));
|
|
76
|
+
if (total !== void 0) tag[totalField] = total;
|
|
77
|
+
}
|
|
66
78
|
for (const [key, values] of Object.entries(props)) {
|
|
67
79
|
if (BASIC_PROPERTY_KEYS[key]) continue;
|
|
68
80
|
if (!values || values.length === 0) continue;
|
|
@@ -81,8 +93,29 @@ function mapPropertiesToExtendedTag(props) {
|
|
|
81
93
|
function mergeTagUpdates(file, tags) {
|
|
82
94
|
const currentProps = file.properties();
|
|
83
95
|
const newProps = normalizeTagInput(tags);
|
|
96
|
+
reconcilePairFields(currentProps, newProps, tags);
|
|
84
97
|
file.setProperties({ ...currentProps, ...newProps });
|
|
85
98
|
}
|
|
99
|
+
function reconcilePairFields(currentProps, newProps, input) {
|
|
100
|
+
const pairs = [
|
|
101
|
+
["trackNumber", "totalTracks", "track"],
|
|
102
|
+
["discNumber", "totalDiscs", "discNumber"]
|
|
103
|
+
];
|
|
104
|
+
for (const [rawKey, totalKey, numericKey] of pairs) {
|
|
105
|
+
const incoming = newProps[rawKey]?.[0];
|
|
106
|
+
if (incoming?.includes("/")) {
|
|
107
|
+
newProps[totalKey] = [];
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const numericOnly = input[numericKey] !== void 0 && input[rawKey] === void 0;
|
|
111
|
+
if (!numericOnly || incoming === void 0) continue;
|
|
112
|
+
const existing = currentProps[rawKey]?.[0];
|
|
113
|
+
const slash = existing?.indexOf("/") ?? -1;
|
|
114
|
+
if (existing !== void 0 && slash !== -1) {
|
|
115
|
+
newProps[rawKey] = [`${incoming}${existing.slice(slash)}`];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
86
119
|
function normalizeTagInput(input) {
|
|
87
120
|
const props = {};
|
|
88
121
|
for (const field of [
|
|
@@ -105,6 +138,9 @@ function normalizeTagInput(input) {
|
|
|
105
138
|
if (input.track !== void 0) {
|
|
106
139
|
props.trackNumber = [String(input.track)];
|
|
107
140
|
}
|
|
141
|
+
if (input.trackNumber !== void 0) {
|
|
142
|
+
props.trackNumber = Array.isArray(input.trackNumber) ? input.trackNumber : [input.trackNumber];
|
|
143
|
+
}
|
|
108
144
|
for (const [field, val] of Object.entries(input)) {
|
|
109
145
|
if (BASIC_FIELDS.has(field) || val === void 0) continue;
|
|
110
146
|
if (field === "compilation") {
|
|
@@ -117,6 +153,12 @@ function normalizeTagInput(input) {
|
|
|
117
153
|
props[field] = val;
|
|
118
154
|
}
|
|
119
155
|
}
|
|
156
|
+
for (const [rawField, totalField] of [
|
|
157
|
+
["trackNumber", "totalTracks"],
|
|
158
|
+
["discNumber", "totalDiscs"]
|
|
159
|
+
]) {
|
|
160
|
+
if (props[rawField]?.[0]?.includes("/")) delete props[totalField];
|
|
161
|
+
}
|
|
120
162
|
return props;
|
|
121
163
|
}
|
|
122
164
|
export {
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.6.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/src/version.js
CHANGED
package/dist/taglib-wasi.wasm
CHANGED
|
Binary file
|
package/dist/taglib-web.wasm
CHANGED
|
Binary file
|