@hyperframes/producer 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +5 -5
- package/dist/index.js +88 -63
- package/dist/index.js.map +4 -4
- package/dist/public-server.js +88 -63
- package/dist/public-server.js.map +4 -4
- package/dist/services/htmlCompiler.d.ts.map +1 -1
- package/dist/services/renderOrchestrator.d.ts +5 -0
- package/dist/services/renderOrchestrator.d.ts.map +1 -1
- package/dist/utils/paths.d.ts +35 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/public-server.js
CHANGED
|
@@ -57866,7 +57866,7 @@ var require_util2 = __commonJS({
|
|
|
57866
57866
|
}
|
|
57867
57867
|
path12 = url.path;
|
|
57868
57868
|
}
|
|
57869
|
-
var
|
|
57869
|
+
var isAbsolute3 = exports.isAbsolute(path12);
|
|
57870
57870
|
var parts = path12.split(/\/+/);
|
|
57871
57871
|
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
|
|
57872
57872
|
part = parts[i];
|
|
@@ -57886,7 +57886,7 @@ var require_util2 = __commonJS({
|
|
|
57886
57886
|
}
|
|
57887
57887
|
path12 = parts.join("/");
|
|
57888
57888
|
if (path12 === "") {
|
|
57889
|
-
path12 =
|
|
57889
|
+
path12 = isAbsolute3 ? "/" : ".";
|
|
57890
57890
|
}
|
|
57891
57891
|
if (url) {
|
|
57892
57892
|
url.path = path12;
|
|
@@ -57931,7 +57931,7 @@ var require_util2 = __commonJS({
|
|
|
57931
57931
|
exports.isAbsolute = function(aPath) {
|
|
57932
57932
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
57933
57933
|
};
|
|
57934
|
-
function
|
|
57934
|
+
function relative3(aRoot, aPath) {
|
|
57935
57935
|
if (aRoot === "") {
|
|
57936
57936
|
aRoot = ".";
|
|
57937
57937
|
}
|
|
@@ -57950,7 +57950,7 @@ var require_util2 = __commonJS({
|
|
|
57950
57950
|
}
|
|
57951
57951
|
return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
|
|
57952
57952
|
}
|
|
57953
|
-
exports.relative =
|
|
57953
|
+
exports.relative = relative3;
|
|
57954
57954
|
var supportsNullProto = (function() {
|
|
57955
57955
|
var obj = /* @__PURE__ */ Object.create(null);
|
|
57956
57956
|
return !("__proto__" in obj);
|
|
@@ -95503,10 +95503,10 @@ function compareDocumentPosition(nodeA, nodeB) {
|
|
|
95503
95503
|
function uniqueSort(nodes) {
|
|
95504
95504
|
nodes = nodes.filter((node, i, arr) => !arr.includes(node, i + 1));
|
|
95505
95505
|
nodes.sort((a, b) => {
|
|
95506
|
-
const
|
|
95507
|
-
if (
|
|
95506
|
+
const relative3 = compareDocumentPosition(a, b);
|
|
95507
|
+
if (relative3 & DocumentPosition.PRECEDING) {
|
|
95508
95508
|
return -1;
|
|
95509
|
-
} else if (
|
|
95509
|
+
} else if (relative3 & DocumentPosition.FOLLOWING) {
|
|
95510
95510
|
return 1;
|
|
95511
95511
|
}
|
|
95512
95512
|
return 0;
|
|
@@ -103853,12 +103853,20 @@ async function createCaptureSession(serverUrl, outputDir, options, onBeforeCaptu
|
|
|
103853
103853
|
config: config2
|
|
103854
103854
|
};
|
|
103855
103855
|
}
|
|
103856
|
+
function isFontResourceError(type, text, locationUrl) {
|
|
103857
|
+
if (type !== "error") return false;
|
|
103858
|
+
if (!text.startsWith("Failed to load resource")) return false;
|
|
103859
|
+
return /fonts\.googleapis|fonts\.gstatic|\.(woff2?|ttf|otf)(\b|$)/i.test(
|
|
103860
|
+
`${locationUrl} ${text}`
|
|
103861
|
+
);
|
|
103862
|
+
}
|
|
103856
103863
|
async function initializeSession(session) {
|
|
103857
103864
|
const { page, serverUrl } = session;
|
|
103858
103865
|
page.on("console", (msg) => {
|
|
103859
103866
|
const type = msg.type();
|
|
103860
103867
|
const text = msg.text();
|
|
103861
|
-
const
|
|
103868
|
+
const locationUrl = msg.location()?.url ?? "";
|
|
103869
|
+
const isFontLoadError = isFontResourceError(type, text, locationUrl);
|
|
103862
103870
|
const isResourceLoadError = type === "error" && text.startsWith("Failed to load resource") && !isFontLoadError;
|
|
103863
103871
|
const prefix = isResourceLoadError ? "[non-blocking]" : type === "error" ? "[Browser:ERROR]" : type === "warn" ? "[Browser:WARN]" : "[Browser]";
|
|
103864
103872
|
if (!isFontLoadError) {
|
|
@@ -105923,7 +105931,7 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
|
|
|
105923
105931
|
}
|
|
105924
105932
|
|
|
105925
105933
|
// src/services/renderOrchestrator.ts
|
|
105926
|
-
import { join as
|
|
105934
|
+
import { join as join15, dirname as dirname10, resolve as resolve10 } from "path";
|
|
105927
105935
|
import { randomUUID } from "crypto";
|
|
105928
105936
|
import { freemem as freemem2 } from "os";
|
|
105929
105937
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -106283,13 +106291,41 @@ function createFileServer2(options) {
|
|
|
106283
106291
|
|
|
106284
106292
|
// src/services/htmlCompiler.ts
|
|
106285
106293
|
import { readFileSync as readFileSync8, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
|
|
106286
|
-
import { join as
|
|
106294
|
+
import { join as join14, dirname as dirname9, resolve as resolve9 } from "path";
|
|
106287
106295
|
import postcss from "postcss";
|
|
106288
106296
|
|
|
106297
|
+
// src/utils/paths.ts
|
|
106298
|
+
import { resolve as resolve8, basename as basename2, join as join12, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
|
|
106299
|
+
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve8(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
106300
|
+
function isPathInside(childPath, parentPath) {
|
|
106301
|
+
const absChild = resolve8(childPath);
|
|
106302
|
+
const absParent = resolve8(parentPath);
|
|
106303
|
+
if (absChild === absParent) return true;
|
|
106304
|
+
const rel = relative2(absParent, absChild);
|
|
106305
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
|
|
106306
|
+
}
|
|
106307
|
+
function toExternalAssetKey(absPath) {
|
|
106308
|
+
if (absPath.startsWith("hf-ext/")) return absPath;
|
|
106309
|
+
let normalised = absPath.replace(/\\/g, "/");
|
|
106310
|
+
normalised = normalised.replace(/^\/\/\?\/UNC\//i, "//");
|
|
106311
|
+
normalised = normalised.replace(/^\/\/\?\//, "");
|
|
106312
|
+
normalised = normalised.replace(/^\/\/([^/]+)\//, "unc/$1/");
|
|
106313
|
+
normalised = normalised.replace(/^\/+/, "");
|
|
106314
|
+
normalised = normalised.replace(/^([A-Za-z]):\/?/, "$1/");
|
|
106315
|
+
return "hf-ext/" + normalised;
|
|
106316
|
+
}
|
|
106317
|
+
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
106318
|
+
const absoluteProjectDir = resolve8(projectDir);
|
|
106319
|
+
const projectName = basename2(absoluteProjectDir);
|
|
106320
|
+
const resolvedOutputPath = outputPath ?? join12(rendersDir, `${projectName}.mp4`);
|
|
106321
|
+
const absoluteOutputPath = resolve8(resolvedOutputPath);
|
|
106322
|
+
return { absoluteProjectDir, absoluteOutputPath };
|
|
106323
|
+
}
|
|
106324
|
+
|
|
106289
106325
|
// src/services/deterministicFonts.ts
|
|
106290
106326
|
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
|
|
106291
106327
|
import { homedir as homedir2 } from "node:os";
|
|
106292
|
-
import { join as
|
|
106328
|
+
import { join as join13 } from "node:path";
|
|
106293
106329
|
|
|
106294
106330
|
// src/services/fontData.generated.ts
|
|
106295
106331
|
var EMBEDDED_FONT_DATA = /* @__PURE__ */ new Map([
|
|
@@ -106567,20 +106603,20 @@ function warnUnresolvedFonts(unresolved) {
|
|
|
106567
106603
|
Docs: https://hyperframes.heygen.com/docs/fonts`
|
|
106568
106604
|
);
|
|
106569
106605
|
}
|
|
106570
|
-
var GOOGLE_FONTS_CACHE_DIR =
|
|
106606
|
+
var GOOGLE_FONTS_CACHE_DIR = join13(homedir2(), ".cache", "hyperframes", "fonts");
|
|
106571
106607
|
var WOFF2_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
|
|
106572
106608
|
function fontSlug(familyName) {
|
|
106573
106609
|
return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
106574
106610
|
}
|
|
106575
106611
|
function fontCacheDir(slug) {
|
|
106576
|
-
const dir =
|
|
106612
|
+
const dir = join13(GOOGLE_FONTS_CACHE_DIR, slug);
|
|
106577
106613
|
if (!existsSync13(dir)) {
|
|
106578
106614
|
mkdirSync8(dir, { recursive: true });
|
|
106579
106615
|
}
|
|
106580
106616
|
return dir;
|
|
106581
106617
|
}
|
|
106582
106618
|
function cachedWoff2Path(slug, weight, style) {
|
|
106583
|
-
return
|
|
106619
|
+
return join13(fontCacheDir(slug), `${weight}-${style}.woff2`);
|
|
106584
106620
|
}
|
|
106585
106621
|
async function fetchGoogleFont(familyName) {
|
|
106586
106622
|
const slug = fontSlug(familyName);
|
|
@@ -106682,7 +106718,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
|
|
|
106682
106718
|
return { duration: 0, resolvedPath: src };
|
|
106683
106719
|
}
|
|
106684
106720
|
} else if (!filePath.startsWith("/")) {
|
|
106685
|
-
filePath =
|
|
106721
|
+
filePath = join14(baseDir, filePath);
|
|
106686
106722
|
}
|
|
106687
106723
|
if (!existsSync14(filePath)) {
|
|
106688
106724
|
return { duration: 0, resolvedPath: filePath };
|
|
@@ -106748,7 +106784,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
106748
106784
|
const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
|
|
106749
106785
|
const absoluteStart = parentOffset + elStart;
|
|
106750
106786
|
const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
|
|
106751
|
-
const filePath =
|
|
106787
|
+
const filePath = resolve9(projectDir, srcPath);
|
|
106752
106788
|
if (visited.has(filePath)) {
|
|
106753
106789
|
continue;
|
|
106754
106790
|
}
|
|
@@ -106948,7 +106984,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
106948
106984
|
if (!srcPath) continue;
|
|
106949
106985
|
let compHtml = subCompositions.get(srcPath) || null;
|
|
106950
106986
|
if (!compHtml) {
|
|
106951
|
-
const filePath =
|
|
106987
|
+
const filePath = resolve9(projectDir, srcPath);
|
|
106952
106988
|
if (existsSync14(filePath)) {
|
|
106953
106989
|
compHtml = readFileSync8(filePath, "utf-8");
|
|
106954
106990
|
}
|
|
@@ -107161,7 +107197,7 @@ ${safeText}
|
|
|
107161
107197
|
return result;
|
|
107162
107198
|
}
|
|
107163
107199
|
function collectExternalAssets(html, projectDir) {
|
|
107164
|
-
const absProjectDir =
|
|
107200
|
+
const absProjectDir = resolve9(projectDir);
|
|
107165
107201
|
const externalAssets = /* @__PURE__ */ new Map();
|
|
107166
107202
|
const CSS_URL_RE2 = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
|
|
107167
107203
|
function processPath(rawPath) {
|
|
@@ -107169,12 +107205,12 @@ function collectExternalAssets(html, projectDir) {
|
|
|
107169
107205
|
if (!trimmed || trimmed.startsWith("/") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("//") || trimmed.startsWith("data:") || trimmed.startsWith("#")) {
|
|
107170
107206
|
return null;
|
|
107171
107207
|
}
|
|
107172
|
-
const absPath =
|
|
107173
|
-
if (
|
|
107208
|
+
const absPath = resolve9(absProjectDir, trimmed);
|
|
107209
|
+
if (isPathInside(absPath, absProjectDir)) {
|
|
107174
107210
|
return null;
|
|
107175
107211
|
}
|
|
107176
107212
|
if (!existsSync14(absPath)) return null;
|
|
107177
|
-
const safeKey =
|
|
107213
|
+
const safeKey = toExternalAssetKey(absPath);
|
|
107178
107214
|
externalAssets.set(safeKey, absPath);
|
|
107179
107215
|
return safeKey;
|
|
107180
107216
|
}
|
|
@@ -107246,7 +107282,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
107246
107282
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
107247
107283
|
for (const video of videos) {
|
|
107248
107284
|
if (isHttpUrl(video.src)) continue;
|
|
107249
|
-
const videoPath =
|
|
107285
|
+
const videoPath = resolve9(projectDir, video.src);
|
|
107250
107286
|
const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
|
|
107251
107287
|
Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
|
|
107252
107288
|
if (analysis.isProblematic) {
|
|
@@ -107473,17 +107509,17 @@ function installDebugLogger(logPath, log = defaultLogger) {
|
|
|
107473
107509
|
};
|
|
107474
107510
|
}
|
|
107475
107511
|
function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
107476
|
-
const compileDir =
|
|
107512
|
+
const compileDir = join15(workDir, "compiled");
|
|
107477
107513
|
mkdirSync10(compileDir, { recursive: true });
|
|
107478
|
-
writeFileSync4(
|
|
107514
|
+
writeFileSync4(join15(compileDir, "index.html"), compiled.html, "utf-8");
|
|
107479
107515
|
for (const [srcPath, html] of compiled.subCompositions) {
|
|
107480
|
-
const outPath =
|
|
107516
|
+
const outPath = join15(compileDir, srcPath);
|
|
107481
107517
|
mkdirSync10(dirname10(outPath), { recursive: true });
|
|
107482
107518
|
writeFileSync4(outPath, html, "utf-8");
|
|
107483
107519
|
}
|
|
107484
107520
|
for (const [relativePath, absolutePath] of compiled.externalAssets) {
|
|
107485
|
-
const outPath =
|
|
107486
|
-
if (!outPath
|
|
107521
|
+
const outPath = resolve10(join15(compileDir, relativePath));
|
|
107522
|
+
if (!isPathInside(outPath, compileDir)) {
|
|
107487
107523
|
console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
|
|
107488
107524
|
continue;
|
|
107489
107525
|
}
|
|
@@ -107511,7 +107547,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
|
107511
107547
|
})),
|
|
107512
107548
|
subCompositions: Array.from(compiled.subCompositions.keys())
|
|
107513
107549
|
};
|
|
107514
|
-
writeFileSync4(
|
|
107550
|
+
writeFileSync4(join15(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
|
|
107515
107551
|
}
|
|
107516
107552
|
}
|
|
107517
107553
|
function createRenderJob(config2) {
|
|
@@ -107555,9 +107591,9 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
|
|
|
107555
107591
|
}
|
|
107556
107592
|
async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
|
|
107557
107593
|
const moduleDir = dirname10(fileURLToPath3(import.meta.url));
|
|
107558
|
-
const producerRoot = process.env.PRODUCER_RENDERS_DIR ?
|
|
107559
|
-
const debugDir =
|
|
107560
|
-
const workDir = job.config.debug ?
|
|
107594
|
+
const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve10(process.env.PRODUCER_RENDERS_DIR, "..") : resolve10(moduleDir, "../..");
|
|
107595
|
+
const debugDir = join15(producerRoot, ".debug");
|
|
107596
|
+
const workDir = job.config.debug ? join15(debugDir, job.id) : join15(dirname10(outputPath), `work-${job.id}`);
|
|
107561
107597
|
const pipelineStart = Date.now();
|
|
107562
107598
|
const log = job.config.logger ?? defaultLogger;
|
|
107563
107599
|
let fileServer = null;
|
|
@@ -107565,7 +107601,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107565
107601
|
let lastBrowserConsole = [];
|
|
107566
107602
|
let restoreLogger = null;
|
|
107567
107603
|
const perfStages = {};
|
|
107568
|
-
const perfOutputPath =
|
|
107604
|
+
const perfOutputPath = join15(workDir, "perf-summary.json");
|
|
107569
107605
|
const cfg = { ...job.config.producerConfig ?? resolveConfig() };
|
|
107570
107606
|
const outputFormat = job.config.format ?? "mp4";
|
|
107571
107607
|
const isWebm = outputFormat === "webm";
|
|
@@ -107587,19 +107623,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107587
107623
|
assertNotAborted();
|
|
107588
107624
|
if (!existsSync15(workDir)) mkdirSync10(workDir, { recursive: true });
|
|
107589
107625
|
if (job.config.debug) {
|
|
107590
|
-
const logPath =
|
|
107626
|
+
const logPath = join15(workDir, "render.log");
|
|
107591
107627
|
restoreLogger = installDebugLogger(logPath, log);
|
|
107592
107628
|
}
|
|
107593
107629
|
const entryFile = job.config.entryFile || "index.html";
|
|
107594
|
-
let htmlPath =
|
|
107630
|
+
let htmlPath = join15(projectDir, entryFile);
|
|
107595
107631
|
if (!existsSync15(htmlPath)) {
|
|
107596
107632
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
107597
107633
|
}
|
|
107598
107634
|
assertNotAborted();
|
|
107599
107635
|
const rawEntry = readFileSync9(htmlPath, "utf-8");
|
|
107600
107636
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
107601
|
-
const wrapperPath =
|
|
107602
|
-
const projectIndexPath =
|
|
107637
|
+
const wrapperPath = join15(workDir, "standalone-entry.html");
|
|
107638
|
+
const projectIndexPath = join15(projectDir, "index.html");
|
|
107603
107639
|
if (!existsSync15(projectIndexPath)) {
|
|
107604
107640
|
throw new Error(
|
|
107605
107641
|
`Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
|
|
@@ -107623,7 +107659,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107623
107659
|
const stage1Start = Date.now();
|
|
107624
107660
|
updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
|
|
107625
107661
|
const compileStart = Date.now();
|
|
107626
|
-
let compiled = await compileForRender(projectDir, htmlPath,
|
|
107662
|
+
let compiled = await compileForRender(projectDir, htmlPath, join15(workDir, "downloads"));
|
|
107627
107663
|
assertNotAborted();
|
|
107628
107664
|
perfStages.compileOnlyMs = Date.now() - compileStart;
|
|
107629
107665
|
writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
|
|
@@ -107652,7 +107688,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107652
107688
|
reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
|
|
107653
107689
|
fileServer = await createFileServer2({
|
|
107654
107690
|
projectDir,
|
|
107655
|
-
compiledDir:
|
|
107691
|
+
compiledDir: join15(workDir, "compiled"),
|
|
107656
107692
|
port: 0
|
|
107657
107693
|
});
|
|
107658
107694
|
assertNotAborted();
|
|
@@ -107665,7 +107701,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107665
107701
|
};
|
|
107666
107702
|
probeSession = await createCaptureSession(
|
|
107667
107703
|
fileServer.url,
|
|
107668
|
-
|
|
107704
|
+
join15(workDir, "probe"),
|
|
107669
107705
|
captureOpts,
|
|
107670
107706
|
null,
|
|
107671
107707
|
cfg
|
|
@@ -107697,7 +107733,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107697
107733
|
compiled,
|
|
107698
107734
|
resolutions,
|
|
107699
107735
|
projectDir,
|
|
107700
|
-
|
|
107736
|
+
join15(workDir, "downloads")
|
|
107701
107737
|
);
|
|
107702
107738
|
assertNotAborted();
|
|
107703
107739
|
composition.videos = compiled.videos;
|
|
@@ -107832,12 +107868,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107832
107868
|
const stage2Start = Date.now();
|
|
107833
107869
|
updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
|
|
107834
107870
|
let frameLookup = null;
|
|
107835
|
-
const compiledDir =
|
|
107871
|
+
const compiledDir = join15(workDir, "compiled");
|
|
107836
107872
|
if (composition.videos.length > 0) {
|
|
107837
107873
|
const extractionResult = await extractAllVideoFrames(
|
|
107838
107874
|
composition.videos,
|
|
107839
107875
|
projectDir,
|
|
107840
|
-
{ fps: job.config.fps, outputDir:
|
|
107876
|
+
{ fps: job.config.fps, outputDir: join15(workDir, "video-frames") },
|
|
107841
107877
|
abortSignal,
|
|
107842
107878
|
void 0,
|
|
107843
107879
|
compiledDir
|
|
@@ -107871,13 +107907,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107871
107907
|
}
|
|
107872
107908
|
const stage3Start = Date.now();
|
|
107873
107909
|
updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
|
|
107874
|
-
const audioOutputPath =
|
|
107910
|
+
const audioOutputPath = join15(workDir, "audio.aac");
|
|
107875
107911
|
let hasAudio = false;
|
|
107876
107912
|
if (composition.audios.length > 0) {
|
|
107877
107913
|
const audioResult = await processCompositionAudio(
|
|
107878
107914
|
composition.audios,
|
|
107879
107915
|
projectDir,
|
|
107880
|
-
|
|
107916
|
+
join15(workDir, "audio-work"),
|
|
107881
107917
|
audioOutputPath,
|
|
107882
107918
|
job.duration,
|
|
107883
107919
|
abortSignal,
|
|
@@ -107895,12 +107931,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107895
107931
|
if (!fileServer) {
|
|
107896
107932
|
fileServer = await createFileServer2({
|
|
107897
107933
|
projectDir,
|
|
107898
|
-
compiledDir:
|
|
107934
|
+
compiledDir: join15(workDir, "compiled"),
|
|
107899
107935
|
port: 0
|
|
107900
107936
|
});
|
|
107901
107937
|
assertNotAborted();
|
|
107902
107938
|
}
|
|
107903
|
-
const framesDir =
|
|
107939
|
+
const framesDir = join15(workDir, "captured-frames");
|
|
107904
107940
|
if (!existsSync15(framesDir)) mkdirSync10(framesDir, { recursive: true });
|
|
107905
107941
|
const captureOptions = {
|
|
107906
107942
|
width,
|
|
@@ -107912,7 +107948,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107912
107948
|
const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
|
|
107913
107949
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
107914
107950
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
107915
|
-
const videoOnlyPath =
|
|
107951
|
+
const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
|
|
107916
107952
|
const preset = getEncoderPreset(job.config.quality, outputFormat);
|
|
107917
107953
|
const effectiveQuality = job.config.crf ?? preset.quality;
|
|
107918
107954
|
const effectiveBitrate = job.config.videoBitrate;
|
|
@@ -108188,7 +108224,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108188
108224
|
}
|
|
108189
108225
|
if (job.config.debug) {
|
|
108190
108226
|
if (existsSync15(outputPath)) {
|
|
108191
|
-
const debugOutput =
|
|
108227
|
+
const debugOutput = join15(workDir, `output${videoExt}`);
|
|
108192
108228
|
copyFileSync2(outputPath, debugOutput);
|
|
108193
108229
|
}
|
|
108194
108230
|
} else {
|
|
@@ -108283,7 +108319,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108283
108319
|
|
|
108284
108320
|
// src/services/hyperframeLint.ts
|
|
108285
108321
|
import { existsSync as existsSync16, readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
|
|
108286
|
-
import { resolve as
|
|
108322
|
+
import { resolve as resolve11, join as join16 } from "node:path";
|
|
108287
108323
|
function isStringRecord(value) {
|
|
108288
108324
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
108289
108325
|
return false;
|
|
@@ -108310,7 +108346,7 @@ function pickEntryFile(files, preferredEntryFile) {
|
|
|
108310
108346
|
return null;
|
|
108311
108347
|
}
|
|
108312
108348
|
function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
108313
|
-
const absProjectDir =
|
|
108349
|
+
const absProjectDir = resolve11(projectDir);
|
|
108314
108350
|
if (!existsSync16(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
|
|
108315
108351
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
108316
108352
|
}
|
|
@@ -108318,7 +108354,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
108318
108354
|
(value) => typeof value === "string" && value.trim().length > 0
|
|
108319
108355
|
);
|
|
108320
108356
|
for (const entryFile of entryCandidates) {
|
|
108321
|
-
const absoluteEntryPath =
|
|
108357
|
+
const absoluteEntryPath = resolve11(absProjectDir, entryFile);
|
|
108322
108358
|
if (!absoluteEntryPath.startsWith(absProjectDir)) {
|
|
108323
108359
|
return { error: `Entry file must stay inside project directory: ${entryFile}` };
|
|
108324
108360
|
}
|
|
@@ -108331,7 +108367,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
108331
108367
|
}
|
|
108332
108368
|
}
|
|
108333
108369
|
return {
|
|
108334
|
-
error: `No HTML entry file found in project directory: ${
|
|
108370
|
+
error: `No HTML entry file found in project directory: ${join16(absProjectDir, preferredEntryFile || "index.html")}`
|
|
108335
108371
|
};
|
|
108336
108372
|
}
|
|
108337
108373
|
function prepareHyperframeLintBody(body) {
|
|
@@ -108371,17 +108407,6 @@ function runHyperframeLint(prepared) {
|
|
|
108371
108407
|
return lintHyperframeHtml(prepared.html, { filePath: prepared.entryFile });
|
|
108372
108408
|
}
|
|
108373
108409
|
|
|
108374
|
-
// src/utils/paths.ts
|
|
108375
|
-
import { resolve as resolve11, basename as basename2, join as join16 } from "node:path";
|
|
108376
|
-
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve11(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
108377
|
-
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
108378
|
-
const absoluteProjectDir = resolve11(projectDir);
|
|
108379
|
-
const projectName = basename2(absoluteProjectDir);
|
|
108380
|
-
const resolvedOutputPath = outputPath ?? join16(rendersDir, `${projectName}.mp4`);
|
|
108381
|
-
const absoluteOutputPath = resolve11(resolvedOutputPath);
|
|
108382
|
-
return { absoluteProjectDir, absoluteOutputPath };
|
|
108383
|
-
}
|
|
108384
|
-
|
|
108385
108410
|
// src/utils/semaphore.ts
|
|
108386
108411
|
var Semaphore = class {
|
|
108387
108412
|
constructor(maxConcurrent) {
|