@openanime/ass2esl
Version:
Utilities to convert Advanced SubStation Alpha (ASS) to Expressive Subtitle Language (ESL)
186 lines (184 loc) • 8 kB
JavaScript
import {
diffObj,
formatHclValue,
quoteString,
secondsToMilliseconds,
transformAssTextToEsl
} from "./chunk-ZLUXC5RC.js";
import {
CUE_PROPERTY_MAP,
TAG_PROPERTY_MAP,
TEXT_STYLE_TAGS,
VALID_CUE_PROPS
} from "./chunk-WA7VBIH5.js";
import {
__name
} from "./chunk-7QVYU63E.js";
// src/cue-processor.ts
function calculateEffectiveMargins(cueMarginData, styleMargins) {
const effective = {};
const styleL = styleMargins.MarginL ?? 0;
const styleR = styleMargins.MarginR ?? 0;
const styleV = styleMargins.MarginV ?? 0;
const effL = cueMarginData?.left !== null && cueMarginData?.left !== void 0 ? cueMarginData.left : styleL;
const effR = cueMarginData?.right !== null && cueMarginData?.right !== void 0 ? cueMarginData.right : styleR;
const effV = cueMarginData?.vertical !== null && cueMarginData?.vertical !== void 0 ? cueMarginData.vertical : styleV;
if (effL !== 0) effective.left = effL;
if (effR !== 0) effective.right = effR;
if (effV !== 0) {
effective.top = effV;
effective.bottom = effV;
}
return effective;
}
__name(calculateEffectiveMargins, "calculateEffectiveMargins");
function processDialogues(dialogues, processedStylesMap, motionIdGenerator) {
const cuesHCLParts = [];
const motionsHCLParts = [];
let autoGeneratedStylesHCL = "";
for (const cue of dialogues) {
const fragments = cue.slices?.[0]?.fragments || [];
const firstFragment = cue.slices?.[0]?.fragments?.[0];
if (!firstFragment?.text) {
continue;
}
let textContent = firstFragment?.text || "";
if (fragments.length > 1) {
for (let index = fragments.length - 1; index > 0; index--) {
const fragmentBefore = fragments[index - 1];
const fragment = fragments[index];
const autoGenerateStyleDiff = diffObj(fragmentBefore.tag, fragment.tag);
let generatedName = false;
for (const [key, value] of Object.entries(autoGenerateStyleDiff)) {
const getCorresponding = TAG_PROPERTY_MAP[key];
if (!getCorresponding) continue;
if (!generatedName) {
const autoGenerateStyleName = `auto-generated-${motionIdGenerator.next()}`;
autoGeneratedStylesHCL += `style ${quoteString(autoGenerateStyleName)} {
`;
generatedName = true;
fragment.text = `<style name="${autoGenerateStyleName}">${fragment.text}</style>`;
}
autoGeneratedStylesHCL += ` ${getCorresponding} = ${value}
`;
}
if (generatedName) {
autoGeneratedStylesHCL += `}`;
}
textContent = textContent + fragment.text;
}
}
const cueHCLProps = [];
const activeTextStyles = /* @__PURE__ */ new Set();
const motionNamesForCue = [];
const motionOutNamesForCue = [];
let currentPosition = null;
const styleName = cue.style;
const associatedStyle = processedStylesMap.get(styleName);
associatedStyle?.features.forEach((feature) => activeTextStyles.add(feature));
const margins = calculateEffectiveMargins(cue.margin, associatedStyle?.margins || {});
if (margins.bottom !== void 0) cueHCLProps.push(` margin_bottom = ${margins.bottom}`);
if (margins.top !== void 0) cueHCLProps.push(` margin_top = ${margins.top}`);
if (margins.left !== void 0) cueHCLProps.push(` margin_left = ${margins.left}`);
if (margins.right !== void 0) cueHCLProps.push(` margin_right = ${margins.right}`);
for (const [assPropName, assPropValue] of Object.entries(cue)) {
if (!VALID_CUE_PROPS.includes(assPropName) || assPropValue === null || assPropValue === void 0) continue;
const eslPropName = CUE_PROPERTY_MAP[assPropName];
if (eslPropName === "slices" && fragments.length === 1) {
const tag = firstFragment.tag;
if (tag) {
if (tag.t) {
for (const transform of tag.t) {
const motionName = `auto-generated-${motionIdGenerator.next()}`;
motionNamesForCue.push(motionName);
const delay = secondsToMilliseconds(cue.start) + (transform.t1 || 0);
const duration = Math.max(0, (transform.t2 || 0) - (transform.t1 || 0));
motionsHCLParts.push(`motion ${quoteString(motionName)} {`);
motionsHCLParts.push(` delay = ${delay}`);
motionsHCLParts.push(` duration = ${duration}`);
motionsHCLParts.push(` easing = "linear"`);
motionsHCLParts.push(`}`);
}
}
if (tag.i === 1) activeTextStyles.add("Italic");
else if (tag.i === 0) activeTextStyles.delete("Italic");
if (tag.b === 1) activeTextStyles.add("Bold");
else if (tag.b === 0) activeTextStyles.delete("Bold");
}
} else if (eslPropName === "position" && cue.pos) {
currentPosition = [
cue.pos.x,
cue.pos.y
];
} else if (eslPropName === "move" && cue.move) {
currentPosition = [
cue.move.x1,
cue.move.y1
];
const motionName = `auto-generated-${motionIdGenerator.next()}`;
motionNamesForCue.push(motionName);
const duration = Math.max(0, (cue.move.t2 || 0) - (cue.move.t1 || 0));
motionsHCLParts.push(`motion ${quoteString(motionName)} {`);
motionsHCLParts.push(` duration = ${duration}`);
motionsHCLParts.push(` easing = "linear"`);
motionsHCLParts.push(` position = [${cue.move.x2}, ${cue.move.y2}]`);
motionsHCLParts.push(`}`);
} else if (eslPropName === "fade") {
if (cue.fade.type === "fad") {
const motionName = `auto-generated-${motionIdGenerator.next()}`;
cueHCLProps.push(` opacity = 0`);
motionNamesForCue.push(motionName);
motionsHCLParts.push(`motion ${quoteString(motionName)} {`);
motionsHCLParts.push(` duration = ${cue.fade.t1}`);
motionsHCLParts.push(` easing = "linear"`);
motionsHCLParts.push(` opacity = 1`);
motionsHCLParts.push(`}`);
if (cue.fade.t2 > 1) {
const motionOutName = `auto-generated-${motionIdGenerator.next()}`;
motionOutNamesForCue.push(motionOutName);
motionsHCLParts.push(`motion ${quoteString(motionOutName)} {`);
motionsHCLParts.push(` duration = ${cue.fade.t2}`);
motionsHCLParts.push(` easing = "linear"`);
motionsHCLParts.push(` opacity = 0`);
motionsHCLParts.push(`}`);
}
}
} else if (eslPropName !== "slices" && eslPropName !== "position" && eslPropName !== "move") {
cueHCLProps.push(` ${eslPropName} = ${formatHclValue(eslPropName, assPropValue)}`);
}
}
if (motionNamesForCue.length > 0) {
const motionRefs = motionNamesForCue.map((name) => quoteString(name)).join(", ");
cueHCLProps.push(` motion_in = [${motionRefs}]`);
}
if (motionOutNamesForCue.length > 0) {
const motionRefs = motionOutNamesForCue.map((name) => quoteString(name)).join(", ");
cueHCLProps.push(` motion_out = [${motionRefs}]`);
}
if (currentPosition) {
cueHCLProps.push(` position = [${currentPosition[0]}, ${currentPosition[1]}]`);
}
if (textContent) {
let eslText = transformAssTextToEsl(textContent);
const sortedStyles = Array.from(activeTextStyles).sort();
for (const styleFeature of sortedStyles) {
const tagName = TEXT_STYLE_TAGS[styleFeature];
if (tagName) {
eslText = `<${tagName}>${eslText}</${tagName}>`;
}
}
cueHCLProps.push(` text = ${formatHclValue("text", eslText)}`);
}
cuesHCLParts.push(`cue {`, ...cueHCLProps.sort(), `}`);
}
return {
cuesHCL: cuesHCLParts.join("\n"),
motionsHCL: motionsHCLParts.join("\n"),
autoGeneratedStylesHCL
};
}
__name(processDialogues, "processDialogues");
export {
processDialogues
};
//# sourceMappingURL=chunk-AF6JKCCH.js.map