Files

47 lines
2.4 KiB
JavaScript

// Render: stitch the cut into one file and keep it in the media bin.
import { offer } from "../../shell/actions.js";
import { composer as c } from "../../composer/composer.js";
import { call } from "../../shell/api.js";
import { clipSpecs } from "./clips.js";
import { RENDER, runJob } from "./job.js";
export default {
id: "render",
mount: "timeline.actions",
needs: ["project"],
modules: ["render"],
setup({ host, app }) {
const p = app.project;
let busy = false, node = null;
const tell = (text) => c.toast.warn({ text });
async function render() {
const open = p.project, { clips, missing } = clipSpecs(open);
if (!clips.length) return tell("Nothing to render: generate at least one clip first.");
if (missing) tell(`${missing} scene(s) have no render yet and are left out.`);
busy = true; draw();
try {
await p.flush();
const state = await runJob(`${RENDER}/projects/${open.id}/render`, { clips, real_fps: p.pref("renderRealFps", false) === true });
if (state.state !== "done") return tell(state.detail || "The render failed.");
const { media } = await call("POST", `${RENDER}/import-clip`, { clip: state.media });
if (app.say) app.say("media"); // the bin shows it now
c.toast.good({ text: `Rendered: saved to the media bin as ${media.name}.` });
} catch (err) { tell(err.message); } finally { busy = false; draw(); }
}
function draw() {
const next = c.button.sm({ label: busy ? "Rendering…" : "⧉ Render", tone: "render", title: "Join the generated clips into one video and save it in the media bin", disabled: busy || !p.project, onClick: render }).node;
if (node) node.replaceWith(next); else host.append(next);
node = next;
}
app.editorSettings.push(() => c.region.stack({ gap: "md", children: [
c.label.section({ text: "Render" }),
c.toggle.default({ label: "Keep the clips' own frame rate", hint: "Off: the final video uses the project's frame rate. On: the fastest clip's rate, so no frames are dropped.",
checked: p.pref("renderRealFps", false) === true, onChange: (v) => p.setPref("renderRealFps", v) })] }));
draw();
const offered = offer(app, { id: "render-final", label: "Render", icon: "⧉", run: () => { if (!busy && p.project) render(); } });
const off = app.on(() => { if (Boolean(p.project) === node.disabled) draw(); });
return () => { off(); offered(); };
},
};