taglib-wasm
Version:
TagLib-Wasm is the universal tagging library for TypeScript/JavaScript platforms: Browsers, Node.js, Deno, Bun, Cloudflare Workers, and Electron apps
122 lines (121 loc) • 4.08 kB
JavaScript
function isValidBitrateMode(value) {
return value === "CBR" || value === "VBR" || value === "ABR";
}
function wrapEmbindHandle(raw) {
const stagedId3v2Frames = {};
const overrides = {
getTagData() {
const tw = raw.getTag();
return {
title: tw.title(),
artist: tw.artist(),
album: tw.album(),
comment: tw.comment(),
genre: tw.genre(),
year: tw.year(),
track: tw.track()
};
},
setTagData(data) {
const tw = raw.getTag();
if (data.title !== void 0) tw.setTitle(data.title);
if (data.artist !== void 0) tw.setArtist(data.artist);
if (data.album !== void 0) tw.setAlbum(data.album);
if (data.comment !== void 0) tw.setComment(data.comment);
if (data.genre !== void 0) tw.setGenre(data.genre);
if (data.year !== void 0) tw.setYear(data.year);
if (data.track !== void 0) tw.setTrack(data.track);
},
getBextData() {
const v = raw.getBextData();
if (v === void 0 || v === null) return void 0;
const u8 = v instanceof Uint8Array ? v : new Uint8Array(v);
return u8.length > 0 ? u8 : void 0;
},
setBextData(data) {
raw.setBextData(data ?? null);
},
getIxml() {
const v = raw.getIxml();
return typeof v === "string" && v.length > 0 ? v : void 0;
},
setIxml(data) {
raw.setIxml(
data ?? null
);
},
// Emscripten exposes USLT only through the PropertyMap "LYRICS" key (no
// dedicated Embind binding), so bridge get/setLyrics to get/setProperties.
// Text only — language/description are not surfaced by the PropertyMap.
getLyrics() {
const props = raw.getProperties();
return (props["LYRICS"] ?? []).map((text) => ({
text,
description: "",
language: ""
}));
},
setLyrics(lyrics) {
const handle = raw;
const props = handle.getProperties();
if (lyrics.length > 0) props["LYRICS"] = lyrics.map((l) => l.text);
else delete props["LYRICS"];
handle.setProperties(props);
},
setId3v2Frames(id, data) {
stagedId3v2Frames[id] = data.map((d) => new Uint8Array(d));
raw.setId3v2Frames(id, data);
},
removeId3v2Frames(id) {
stagedId3v2Frames[id] = [];
raw.removeId3v2Frames(id);
},
getStagedId3v2Frames() {
return Object.keys(stagedId3v2Frames).length > 0 ? { ...stagedId3v2Frames } : void 0;
},
hasId3Tags() {
const v = raw.hasId3Tags();
if (!v || typeof v !== "object") return { v1: false, v2: false };
const o = v;
return { v1: o.v1 === true, v2: o.v2 === true };
},
stripId3Tags(opts) {
raw.stripId3Tags(opts);
},
getAudioProperties() {
const pw = raw.getAudioProperties();
if (!pw) return null;
const containerFormat = pw.containerFormat() || "unknown";
const codec = pw.codec() || "unknown";
const mpegVersion = pw.mpegVersion();
const formatVersion = pw.formatVersion();
const bitrateMode = pw.bitrateMode();
return {
duration: pw.lengthInSeconds(),
durationMs: pw.lengthInMilliseconds(),
bitrate: pw.bitrate(),
sampleRate: pw.sampleRate(),
channels: pw.channels(),
bitsPerSample: pw.bitsPerSample(),
codec,
containerFormat,
isLossless: pw.isLossless(),
...mpegVersion > 0 ? { mpegVersion, mpegLayer: pw.mpegLayer() } : {},
...containerFormat === "MP4" || containerFormat === "ASF" ? { isEncrypted: pw.isEncrypted() } : {},
...formatVersion > 0 ? { formatVersion } : {},
...isValidBitrateMode(bitrateMode) ? { bitrateMode } : {},
...codec === "Opus" ? { outputGainDb: pw.outputGainDb() } : {}
};
}
};
return new Proxy(raw, {
get(target, prop, receiver) {
if (prop in overrides) return overrides[prop];
const value = Reflect.get(target, prop, receiver);
return typeof value === "function" ? value.bind(target) : value;
}
});
}
export {
wrapEmbindHandle
};