174 lines
3.9 KiB
TypeScript
174 lines
3.9 KiB
TypeScript
import type { RenderScene, RenderSettings } from "../src/lib/render-schemas";
|
|
import { RESOLUTION_DIMENSIONS } from "../src/lib/render-schemas";
|
|
|
|
export interface NexrenderAsset {
|
|
type: string;
|
|
layerName?: string;
|
|
composition?: string;
|
|
property?: string;
|
|
value?: string | number;
|
|
src?: string;
|
|
width?: number;
|
|
height?: number;
|
|
time?: number;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
export interface NexrenderJob {
|
|
template: {
|
|
src: string;
|
|
composition: string;
|
|
frameStart?: number;
|
|
frameEnd?: number;
|
|
};
|
|
assets: NexrenderAsset[];
|
|
actions?: {
|
|
postrender?: Array<Record<string, unknown>>;
|
|
};
|
|
onRenderProgress?: string;
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
|
|
function layerToAsset(
|
|
layer: RenderScene["layers"][number],
|
|
scene: RenderScene,
|
|
sceneIndex: number
|
|
): NexrenderAsset | null {
|
|
const time = sceneIndex * scene.duration;
|
|
|
|
switch (layer.type) {
|
|
case "text": {
|
|
const text =
|
|
typeof layer.props.text === "string" ? layer.props.text : "Text";
|
|
return {
|
|
type: "data",
|
|
layerName: `Scene${sceneIndex + 1}_Text`,
|
|
composition: scene.name,
|
|
property: "Source Text",
|
|
value: text,
|
|
time,
|
|
};
|
|
}
|
|
case "image": {
|
|
const src = typeof layer.props.src === "string" ? layer.props.src : "";
|
|
if (!src) return null;
|
|
return {
|
|
type: "image",
|
|
layerName: `Scene${sceneIndex + 1}_Image`,
|
|
composition: scene.name,
|
|
src,
|
|
width: layer.width,
|
|
height: layer.height,
|
|
time,
|
|
};
|
|
}
|
|
case "video": {
|
|
const src = typeof layer.props.src === "string" ? layer.props.src : "";
|
|
if (!src) return null;
|
|
return {
|
|
type: "video",
|
|
layerName: `Scene${sceneIndex + 1}_Video`,
|
|
composition: scene.name,
|
|
src,
|
|
time,
|
|
};
|
|
}
|
|
case "shape":
|
|
return {
|
|
type: "data",
|
|
layerName: `Scene${sceneIndex + 1}_Shape`,
|
|
composition: scene.name,
|
|
property: "Opacity",
|
|
value: Math.round(layer.opacity * 100),
|
|
time,
|
|
};
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function buildNexrenderJob(
|
|
scenes: RenderScene[],
|
|
settings: RenderSettings,
|
|
jobId: string,
|
|
outputPath: string
|
|
): NexrenderJob {
|
|
const templateSrc =
|
|
process.env.NEXRENDER_TEMPLATE_SRC ??
|
|
"file:///templates/creatorstudio-base.aep";
|
|
const composition =
|
|
process.env.NEXRENDER_COMPOSITION ?? "CreatorStudio_Main";
|
|
|
|
const { width, height } = RESOLUTION_DIMENSIONS[settings.resolution];
|
|
const totalDuration = scenes.reduce((sum, scene) => sum + scene.duration, 0);
|
|
const frameEnd = Math.ceil(totalDuration * settings.fps);
|
|
|
|
const assets: NexrenderAsset[] = [
|
|
{
|
|
type: "data",
|
|
layerName: "Settings",
|
|
composition,
|
|
property: "Width",
|
|
value: width,
|
|
},
|
|
{
|
|
type: "data",
|
|
layerName: "Settings",
|
|
composition,
|
|
property: "Height",
|
|
value: height,
|
|
},
|
|
{
|
|
type: "data",
|
|
layerName: "Settings",
|
|
composition,
|
|
property: "Frame Rate",
|
|
value: settings.fps,
|
|
},
|
|
];
|
|
|
|
scenes.forEach((scene, sceneIndex) => {
|
|
assets.push({
|
|
type: "data",
|
|
layerName: `Scene${sceneIndex + 1}`,
|
|
composition,
|
|
property: "Duration",
|
|
value: scene.duration,
|
|
time: sceneIndex * scene.duration,
|
|
});
|
|
|
|
const sortedLayers = [...scene.layers].sort(
|
|
(a, b) => a.zIndex - b.zIndex
|
|
);
|
|
|
|
sortedLayers.forEach((layer) => {
|
|
const asset = layerToAsset(layer, scene, sceneIndex);
|
|
if (asset) assets.push(asset);
|
|
});
|
|
});
|
|
|
|
return {
|
|
template: {
|
|
src: templateSrc,
|
|
composition,
|
|
frameStart: 0,
|
|
frameEnd,
|
|
},
|
|
assets,
|
|
actions: {
|
|
postrender: [
|
|
{
|
|
module: "@nexrender/action-copy",
|
|
output: outputPath,
|
|
},
|
|
],
|
|
},
|
|
metadata: {
|
|
jobId,
|
|
resolution: settings.resolution,
|
|
fps: settings.fps,
|
|
format: settings.format,
|
|
},
|
|
};
|
|
}
|