UNPKG

@openanime/ass2esl

Version:

Utilities to convert Advanced SubStation Alpha (ASS) to Expressive Subtitle Language (ESL)

186 lines (184 loc) 8 kB
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