taglib-wasm
Version:
TagLib for TypeScript platforms: Deno, Node.js, Bun, Electron, browsers, and Cloudflare Workers
220 lines (219 loc) • 6.1 kB
JavaScript
import { encode } from "@msgpack/msgpack";
const MSGPACK_ENCODE_OPTIONS = {
// Use the most compact representation
sortKeys: false,
// Maintain field order for consistency
forceFloat32: false,
// Use optimal precision
ignoreUndefined: true,
// Skip undefined fields
initialBufferSize: 2048,
// Start with reasonable buffer size
maxDepth: 32,
// Reasonable nesting limit
// Extension codec for custom types (if needed)
extensionCodec: void 0
};
function encodeTagData(tagData) {
try {
const cleanedData = cleanObject(tagData);
return encode(cleanedData, MSGPACK_ENCODE_OPTIONS);
} catch (error) {
throw new Error(`Failed to encode tag data to MessagePack: ${error}`);
}
}
function encodeAudioProperties(audioProps) {
try {
const cleanedData = cleanObject(audioProps);
return encode(cleanedData, MSGPACK_ENCODE_OPTIONS);
} catch (error) {
throw new Error(
`Failed to encode audio properties to MessagePack: ${error}`
);
}
}
function encodePropertyMap(propertyMap) {
try {
return encode(propertyMap, MSGPACK_ENCODE_OPTIONS);
} catch (error) {
throw new Error(`Failed to encode property map to MessagePack: ${error}`);
}
}
function encodePicture(picture) {
try {
const cleanedPicture = {
...picture,
data: picture.data instanceof Uint8Array ? picture.data : new Uint8Array(picture.data)
};
return encode(cleanedPicture, MSGPACK_ENCODE_OPTIONS);
} catch (error) {
throw new Error(`Failed to encode picture to MessagePack: ${error}`);
}
}
function encodePictureArray(pictures) {
try {
const cleanedPictures = pictures.map((picture) => ({
...picture,
data: picture.data instanceof Uint8Array ? picture.data : new Uint8Array(picture.data)
}));
return encode(cleanedPictures, MSGPACK_ENCODE_OPTIONS);
} catch (error) {
throw new Error(`Failed to encode picture array to MessagePack: ${error}`);
}
}
function encodeMessagePack(data, options = {}) {
try {
const mergedOptions = { ...MSGPACK_ENCODE_OPTIONS, ...options };
const cleanedData = cleanObject(data);
return encode(cleanedData, mergedOptions);
} catch (error) {
throw new Error(`Failed to encode data to MessagePack: ${error}`);
}
}
function encodeMessagePackCompact(data) {
try {
const compactOptions = {
...MSGPACK_ENCODE_OPTIONS,
sortKeys: true,
// Sort keys for better compression
initialBufferSize: 512,
// Start smaller for compact data
forceFloat32: true
// Use smaller floats when possible
};
const cleanedData = cleanObject(data);
return encode(cleanedData, compactOptions);
} catch (error) {
throw new Error(`Failed to encode data to compact MessagePack: ${error}`);
}
}
function cleanObject(obj) {
if (obj === null || obj === void 0) {
return null;
}
if (typeof obj !== "object") {
return obj;
}
if (obj instanceof Uint8Array || obj instanceof Array) {
return obj;
}
if (obj instanceof Date) {
return obj;
}
const cleaned = {};
for (const [key, value] of Object.entries(obj)) {
if (value === void 0) {
continue;
}
if (value === null) {
cleaned[key] = null;
continue;
}
if (typeof value === "string" && value === "") {
continue;
}
if (typeof value === "object") {
cleaned[key] = cleanObject(value);
} else {
cleaned[key] = value;
}
}
return cleaned;
}
function encodeBatchTagData(tagDataArray) {
try {
const cleanedArray = tagDataArray.map((tagData) => cleanObject(tagData));
return encode(cleanedArray, {
...MSGPACK_ENCODE_OPTIONS,
initialBufferSize: 8192,
// Larger buffer for batch data
maxDepth: 16
// Simpler structure for batch
});
} catch (error) {
throw new Error(`Failed to encode batch tag data to MessagePack: ${error}`);
}
}
function* encodeMessagePackStream(dataIterator) {
try {
for (const item of dataIterator) {
const cleanedItem = cleanObject(item);
yield encode(cleanedItem, {
...MSGPACK_ENCODE_OPTIONS,
initialBufferSize: 1024
// Smaller buffer for streaming
});
}
} catch (error) {
throw new Error(`Failed to encode streaming data to MessagePack: ${error}`);
}
}
function estimateMessagePackSize(data) {
try {
const encoded = encode(cleanObject(data), {
...MSGPACK_ENCODE_OPTIONS,
initialBufferSize: 512
});
return encoded.length;
} catch (error) {
const jsonSize = JSON.stringify(data).length;
return Math.floor(jsonSize * 0.75);
}
}
function encodeFastTagData(tagData) {
try {
const fastOptions = {
sortKeys: false,
ignoreUndefined: true,
initialBufferSize: 256,
// Small buffer for essential fields
maxDepth: 8
// Simple structure
};
const cleanedData = cleanObject(tagData);
return encode(cleanedData, fastOptions);
} catch (error) {
throw new Error(`Failed to encode fast tag data to MessagePack: ${error}`);
}
}
function canEncodeToMessagePack(data) {
try {
encode(cleanObject(data), {
...MSGPACK_ENCODE_OPTIONS,
maxDepth: 16,
initialBufferSize: 256
});
return true;
} catch {
return false;
}
}
function compareEncodingEfficiency(data) {
const jsonString = JSON.stringify(data);
const jsonSize = new TextEncoder().encode(jsonString).length;
const messagePackData = encode(cleanObject(data), MSGPACK_ENCODE_OPTIONS);
const messagePackSize = messagePackData.length;
const sizeReduction = (jsonSize - messagePackSize) / jsonSize * 100;
const speedImprovement = 10;
return {
messagePackSize,
jsonSize,
sizeReduction: Math.max(0, sizeReduction),
speedImprovement
};
}
export {
canEncodeToMessagePack,
compareEncodingEfficiency,
encodeAudioProperties,
encodeBatchTagData,
encodeFastTagData,
encodeMessagePack,
encodeMessagePackCompact,
encodeMessagePackStream,
encodePicture,
encodePictureArray,
encodePropertyMap,
encodeTagData,
estimateMessagePackSize
};