taglib-wasm
Version:
TagLib-Wasm is the universal tagging library for TypeScript/JavaScript platforms: Browsers, Node.js, Deno, Bun, Cloudflare Workers, and Electron apps
217 lines (216 loc) • 5.69 kB
JavaScript
import { decode } from "@msgpack/msgpack";
import { errorMessage, MetadataError } from "../errors/classes.js";
import { remapKeysFromTagLib } from "../constants/properties.js";
const MSGPACK_DECODE_OPTIONS = {
useBigInt64: false,
extensionCodec: void 0,
maxStrLength: 1e6,
maxBinLength: 5e7,
maxArrayLength: 1e4,
maxMapLength: 1e3,
maxExtLength: 5e7
};
function decodeTagData(msgpackBuffer) {
try {
const raw = decode(msgpackBuffer, MSGPACK_DECODE_OPTIONS);
return remapKeysFromTagLib(raw);
} catch (error) {
throw new MetadataError(
"read",
`Failed to decode tag data: ${errorMessage(error)}`
);
}
}
function decodeAudioProperties(msgpackBuffer) {
try {
const raw = decode(msgpackBuffer, MSGPACK_DECODE_OPTIONS);
if ("length" in raw && !("duration" in raw)) {
raw.duration = raw.length;
delete raw.length;
}
return raw;
} catch (error) {
throw new MetadataError(
"read",
`Failed to decode audio properties: ${errorMessage(error)}`
);
}
}
function decodePropertyMap(msgpackBuffer) {
try {
return decode(msgpackBuffer, MSGPACK_DECODE_OPTIONS);
} catch (error) {
throw new MetadataError(
"read",
`Failed to decode property map: ${errorMessage(error)}`
);
}
}
function decodePicture(msgpackBuffer) {
try {
const picture = decode(msgpackBuffer, MSGPACK_DECODE_OPTIONS);
coercePictureData(picture);
return picture;
} catch (error) {
throw new MetadataError(
"read",
`Failed to decode picture data: ${errorMessage(error)}`
);
}
}
function decodePictureArray(msgpackBuffer) {
try {
const pictures = decode(msgpackBuffer, MSGPACK_DECODE_OPTIONS);
return pictures.map((picture) => {
coercePictureData(picture);
return picture;
});
} catch (error) {
throw new MetadataError(
"read",
`Failed to decode picture array: ${errorMessage(error)}`
);
}
}
function decodeMessagePack(msgpackBuffer, options = {}) {
try {
const mergedOptions = { ...MSGPACK_DECODE_OPTIONS, ...options };
return decode(msgpackBuffer, mergedOptions);
} catch (error) {
throw new MetadataError(
"read",
`Failed to decode data: ${errorMessage(error)}`
);
}
}
function isAudioProperties(obj) {
return "bitrate" in obj && "sampleRate" in obj && ("length" in obj || "duration" in obj);
}
function isPicture(obj) {
return "mimeType" in obj && "data" in obj;
}
function coercePictureData(obj) {
if (obj.data && !(obj.data instanceof Uint8Array)) {
obj.data = new Uint8Array(obj.data);
}
}
function isTagLike(obj) {
return "title" in obj || "artist" in obj || "album" in obj || "TITLE" in obj || "ARTIST" in obj || "ALBUM" in obj;
}
function isPropertyMap(obj) {
const values = Object.values(obj);
return values.length > 0 && values.every((value) => Array.isArray(value));
}
function decodeMessagePackAuto(msgpackBuffer) {
try {
const decoded = decode(msgpackBuffer, MSGPACK_DECODE_OPTIONS);
if (decoded && typeof decoded === "object") {
const obj = decoded;
if (isAudioProperties(obj)) {
if ("length" in obj && !("duration" in obj)) {
obj.duration = obj.length;
delete obj.length;
}
return obj;
}
if (isPicture(obj)) {
coercePictureData(obj);
return obj;
}
if (isPropertyMap(obj)) return obj;
if (isTagLike(obj)) {
return remapKeysFromTagLib(obj);
}
}
throw new MetadataError(
"read",
`Unexpected non-object MessagePack data: ${typeof decoded}`
);
} catch (error) {
throw new MetadataError(
"read",
`Failed to decode data with auto-detection: ${errorMessage(error)}`
);
}
}
function isValidMessagePack(buffer) {
try {
decode(buffer, {
...MSGPACK_DECODE_OPTIONS,
maxStrLength: 1e3,
maxBinLength: 1e3,
maxArrayLength: 100,
maxMapLength: 100,
maxExtLength: 1e3
});
return true;
} catch {
return false;
}
}
function detectType(decoded) {
if (Array.isArray(decoded)) return "array";
if (decoded instanceof Uint8Array) return "binary";
if (typeof decoded === "object" && decoded !== null) return "map";
if (typeof decoded === "string") return "string";
if (typeof decoded === "number") return "number";
if (typeof decoded === "boolean") return "boolean";
if (decoded === null) return "null";
return "unknown";
}
function getMessagePackInfo(buffer) {
const info = {
isValid: false,
approximateSize: buffer.length,
type: "unknown"
};
if (buffer.length === 0) return info;
try {
const decoded = decode(buffer, {
...MSGPACK_DECODE_OPTIONS,
maxStrLength: 100,
maxBinLength: 100,
maxArrayLength: 10,
maxMapLength: 10,
maxExtLength: 100
});
info.isValid = true;
info.type = detectType(decoded);
} catch {
}
return info;
}
function decodeFastTagData(msgpackBuffer) {
try {
const decoded = decode(msgpackBuffer, {
...MSGPACK_DECODE_OPTIONS,
maxStrLength: 1e4,
maxArrayLength: 100,
maxMapLength: 50
});
return {
title: decoded.title,
artist: decoded.artist,
album: decoded.album,
year: decoded.year,
track: decoded.track
};
} catch (error) {
throw new MetadataError(
"read",
`Failed to decode fast tag data: ${errorMessage(error)}`
);
}
}
export {
decodeAudioProperties,
decodeFastTagData,
decodeMessagePack,
decodeMessagePackAuto,
decodePicture,
decodePictureArray,
decodePropertyMap,
decodeTagData,
getMessagePackInfo,
isValidMessagePack
};