UNPKG

taglib-wasm

Version:

TagLib-Wasm is the universal tagging library for TypeScript/JavaScript platforms: Browsers, Node.js, Deno, Bun, Cloudflare Workers, and Electron apps

154 lines (153 loc) 5.46 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { mp4AtomWireKey, mp4FreeformAtomNames, remapKeysFromTagLib, toTagLibKey } from "../constants/properties.js"; import { MetadataError, UnsupportedFormatError } from "../errors.js"; import { MP4_ITEM_NAMES_KEY } from "./mp4-item-names.js"; import { buildMutableTag } from "./mutable-tag-impl.js"; const LYRICS_PROPERTY_KEY = "lyrics"; const LYRICS_WIRE_KEY = toTagLibKey(LYRICS_PROPERTY_KEY); const EMPTY_KEY_SET = /* @__PURE__ */ new Set(); class BaseAudioFileImpl { constructor(module, fileHandle, sourcePath, originalSource, isPartiallyLoaded = false, partialLoadOptions) { __publicField(this, "module", module); __publicField(this, "fileHandle"); __publicField(this, "cachedAudioProperties", null); __publicField(this, "sourcePath"); __publicField(this, "originalSource"); __publicField(this, "isPartiallyLoaded", false); __publicField(this, "partialLoadOptions"); /** Text-property wire keys in the partial header at load; undefined if full. */ __publicField(this, "partialKeysAtLoad"); this.fileHandle = fileHandle; this.sourcePath = sourcePath; this.originalSource = originalSource; this.isPartiallyLoaded = isPartiallyLoaded; this.partialLoadOptions = partialLoadOptions; this.partialKeysAtLoad = isPartiallyLoaded ? new Set(Object.keys(fileHandle.getProperties())) : void 0; } /** * Wire-key text properties present in the partial header at load but now * absent — the user deleted them. The partial-load reconstruct subtracts these * from its preserve-the-original merge so a deletion persists without wiping * frames beyond the loaded header (taglib-d14). Lyrics are excluded (they ride * their own reconstruct path); empty for a full load. */ partialDeletedPropertyKeys() { if (!this.partialKeysAtLoad) return EMPTY_KEY_SET; const current = new Set(Object.keys(this.handle.getProperties())); const deleted = /* @__PURE__ */ new Set(); for (const key of this.partialKeysAtLoad) { if (key !== LYRICS_WIRE_KEY && !current.has(key)) deleted.add(key); } return deleted; } get handle() { if (!this.fileHandle) { throw new MetadataError("read", "File handle has been disposed"); } return this.fileHandle; } getFormat() { return this.handle.getFormat(); } isFormat(format) { return this.getFormat() === format; } tag() { return buildMutableTag(this.handle); } audioProperties() { if (!this.cachedAudioProperties) { this.cachedAudioProperties = this.handle.getAudioProperties() ?? null; } return this.cachedAudioProperties ?? void 0; } properties() { const remapped = remapKeysFromTagLib(this.handle.getProperties()); delete remapped[LYRICS_PROPERTY_KEY]; return remapped; } setProperties(properties) { const translated = {}; for (const [key, values] of Object.entries(properties)) { if (values !== void 0) translated[toTagLibKey(key)] = values; } if (!(LYRICS_WIRE_KEY in translated)) { const existing = this.handle.getProperties()[LYRICS_WIRE_KEY]; if (existing !== void 0) translated[LYRICS_WIRE_KEY] = existing; } const atomNames = mp4FreeformAtomNames(Object.keys(translated)); if (atomNames.length > 0) translated[MP4_ITEM_NAMES_KEY] = atomNames; this.handle.setProperties(translated); } getProperty(key) { const value = this.handle.getProperty(toTagLibKey(key)); if (value !== "") return value; if (!this.isMP4()) return void 0; const remapped = this.properties()[key]?.[0]; return remapped === "" ? void 0 : remapped; } setProperty(key, value) { const wireKey = toTagLibKey(key); const atomNames = mp4FreeformAtomNames([wireKey]); if (atomNames.length > 0 && this.isMP4()) { this.handle.setProperties({ ...this.handle.getProperties(), [wireKey]: [value], [MP4_ITEM_NAMES_KEY]: atomNames }); return; } this.handle.setProperty(wireKey, value); } isMP4() { return this.handle.isMP4(); } getMP4Item(key) { if (!this.isMP4()) { throw new UnsupportedFormatError(this.getFormat(), ["MP4", "M4A"]); } const wireKey = mp4AtomWireKey(key); const value = wireKey !== void 0 ? this.handle.getProperty(wireKey) : this.handle.getMP4Item(key); return value === "" ? void 0 : value; } setMP4Item(key, value) { if (!this.isMP4()) { throw new UnsupportedFormatError(this.getFormat(), ["MP4", "M4A"]); } const wireKey = mp4AtomWireKey(key); if (wireKey !== void 0) { this.handle.setProperty(wireKey, value); return; } this.handle.setMP4Item(key, value); } removeMP4Item(key) { if (!this.isMP4()) { throw new UnsupportedFormatError(this.getFormat(), ["MP4", "M4A"]); } this.handle.removeMP4Item(key); } isValid() { return this.handle.isValid(); } dispose() { if (this.fileHandle) { this.fileHandle.destroy(); this.fileHandle = null; this.cachedAudioProperties = null; } } [Symbol.dispose]() { this.dispose(); } } export { BaseAudioFileImpl };