mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 15:20:13 +00:00
fix(product-launch): consolidate media brand and audio contracts (#2408)
* fix(product-launch): preserve hoisted media offsets * fix(product-launch): preserve brand font and accent roles * fix(product-launch): honor TTS provider selection * fix(product-launch): preserve approved video geometry * fix(skills): enforce media geometry and font classification * fix(skills): align secondary brand accents
This commit is contained in:
@@ -177,7 +177,7 @@ function escapeHtmlAttr(value) {
|
||||
|
||||
function approvedVideoAttrs(attrs) {
|
||||
const forwarded = [];
|
||||
for (const name of ["id", "src", "poster", "preload", "aria-label"]) {
|
||||
for (const name of ["id", "src", "poster", "preload", "aria-label", "data-media-start"]) {
|
||||
const value = attrValueFrom(attrs, name);
|
||||
if (value !== null) forwarded.push(`${name}="${escapeHtmlAttr(value)}"`);
|
||||
}
|
||||
@@ -187,6 +187,42 @@ function approvedVideoAttrs(attrs) {
|
||||
return forwarded.join(" ");
|
||||
}
|
||||
|
||||
function approvedVideoLayout(attrs) {
|
||||
const names = ["x", "y", "width", "height"];
|
||||
const raw = Object.fromEntries(
|
||||
names.map((name) => [name, attrValueFrom(attrs, `data-frame-video-${name}`)]),
|
||||
);
|
||||
const rawFit = attrValueFrom(attrs, "data-frame-video-fit");
|
||||
const values = Object.fromEntries(names.map((name) => [name, Number(raw[name])]));
|
||||
if (
|
||||
names.some(
|
||||
(name) => raw[name] === null || raw[name].trim() === "" || !Number.isFinite(values[name]),
|
||||
) ||
|
||||
values.width <= 0 ||
|
||||
values.height <= 0
|
||||
) {
|
||||
return {
|
||||
style: null,
|
||||
error:
|
||||
"approved frame video layout data-frame-video-x/y/width/height must all be finite numeric values, with positive width and height",
|
||||
};
|
||||
}
|
||||
|
||||
const fit = rawFit ?? "cover";
|
||||
if (!["cover", "contain", "fill", "none", "scale-down"].includes(fit)) {
|
||||
return {
|
||||
style: null,
|
||||
error:
|
||||
'approved frame video layout data-frame-video-fit must be "cover", "contain", "fill", "none", or "scale-down"',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
style: `position:absolute;left:${values.x}px;top:${values.y}px;width:${values.width}px;height:${values.height}px;object-fit:${fit}`,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
function hoistApprovedVideos(html, label) {
|
||||
const videos = [];
|
||||
const errors = [];
|
||||
@@ -221,7 +257,19 @@ function hoistApprovedVideos(html, label) {
|
||||
);
|
||||
return full;
|
||||
}
|
||||
videos.push({ attrs: approvedVideoAttrs(attrs), inner, start, duration, track });
|
||||
const layout = approvedVideoLayout(attrs);
|
||||
if (layout.error) {
|
||||
errors.push(`${label}: ${layout.error}`);
|
||||
return full;
|
||||
}
|
||||
videos.push({
|
||||
attrs: approvedVideoAttrs(attrs),
|
||||
inner,
|
||||
start,
|
||||
duration,
|
||||
track,
|
||||
layoutStyle: layout.style,
|
||||
});
|
||||
return "<!-- approved frame video hoisted by assemble-index -->";
|
||||
});
|
||||
return { html: repaired, videos, errors };
|
||||
@@ -458,6 +506,7 @@ for (const [frameIndex, m] of mounted.entries()) {
|
||||
body.push(
|
||||
` <video${id} ${video.attrs}`,
|
||||
` class="clip"`,
|
||||
...(video.layoutStyle ? [` style="${video.layoutStyle}"`] : []),
|
||||
` data-start="${globalStart}"`,
|
||||
` data-duration="${r3(video.duration)}"`,
|
||||
` data-track-index="${track}"`,
|
||||
|
||||
Reference in New Issue
Block a user