@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/index.js
CHANGED
|
@@ -57865,7 +57865,7 @@ var require_util2 = __commonJS({
|
|
|
57865
57865
|
}
|
|
57866
57866
|
path12 = url.path;
|
|
57867
57867
|
}
|
|
57868
|
-
var
|
|
57868
|
+
var isAbsolute3 = exports.isAbsolute(path12);
|
|
57869
57869
|
var parts = path12.split(/\/+/);
|
|
57870
57870
|
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
|
|
57871
57871
|
part = parts[i];
|
|
@@ -57885,7 +57885,7 @@ var require_util2 = __commonJS({
|
|
|
57885
57885
|
}
|
|
57886
57886
|
path12 = parts.join("/");
|
|
57887
57887
|
if (path12 === "") {
|
|
57888
|
-
path12 =
|
|
57888
|
+
path12 = isAbsolute3 ? "/" : ".";
|
|
57889
57889
|
}
|
|
57890
57890
|
if (url) {
|
|
57891
57891
|
url.path = path12;
|
|
@@ -57930,7 +57930,7 @@ var require_util2 = __commonJS({
|
|
|
57930
57930
|
exports.isAbsolute = function(aPath) {
|
|
57931
57931
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
57932
57932
|
};
|
|
57933
|
-
function
|
|
57933
|
+
function relative3(aRoot, aPath) {
|
|
57934
57934
|
if (aRoot === "") {
|
|
57935
57935
|
aRoot = ".";
|
|
57936
57936
|
}
|
|
@@ -57949,7 +57949,7 @@ var require_util2 = __commonJS({
|
|
|
57949
57949
|
}
|
|
57950
57950
|
return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
|
|
57951
57951
|
}
|
|
57952
|
-
exports.relative =
|
|
57952
|
+
exports.relative = relative3;
|
|
57953
57953
|
var supportsNullProto = (function() {
|
|
57954
57954
|
var obj = /* @__PURE__ */ Object.create(null);
|
|
57955
57955
|
return !("__proto__" in obj);
|
|
@@ -92714,10 +92714,10 @@ function compareDocumentPosition(nodeA, nodeB) {
|
|
|
92714
92714
|
function uniqueSort(nodes) {
|
|
92715
92715
|
nodes = nodes.filter((node, i, arr) => !arr.includes(node, i + 1));
|
|
92716
92716
|
nodes.sort((a, b) => {
|
|
92717
|
-
const
|
|
92718
|
-
if (
|
|
92717
|
+
const relative3 = compareDocumentPosition(a, b);
|
|
92718
|
+
if (relative3 & DocumentPosition.PRECEDING) {
|
|
92719
92719
|
return -1;
|
|
92720
|
-
} else if (
|
|
92720
|
+
} else if (relative3 & DocumentPosition.FOLLOWING) {
|
|
92721
92721
|
return 1;
|
|
92722
92722
|
}
|
|
92723
92723
|
return 0;
|
|
@@ -101064,12 +101064,20 @@ async function createCaptureSession(serverUrl, outputDir, options, onBeforeCaptu
|
|
|
101064
101064
|
config: config2
|
|
101065
101065
|
};
|
|
101066
101066
|
}
|
|
101067
|
+
function isFontResourceError(type, text, locationUrl) {
|
|
101068
|
+
if (type !== "error") return false;
|
|
101069
|
+
if (!text.startsWith("Failed to load resource")) return false;
|
|
101070
|
+
return /fonts\.googleapis|fonts\.gstatic|\.(woff2?|ttf|otf)(\b|$)/i.test(
|
|
101071
|
+
`${locationUrl} ${text}`
|
|
101072
|
+
);
|
|
101073
|
+
}
|
|
101067
101074
|
async function initializeSession(session) {
|
|
101068
101075
|
const { page, serverUrl } = session;
|
|
101069
101076
|
page.on("console", (msg) => {
|
|
101070
101077
|
const type = msg.type();
|
|
101071
101078
|
const text = msg.text();
|
|
101072
|
-
const
|
|
101079
|
+
const locationUrl = msg.location()?.url ?? "";
|
|
101080
|
+
const isFontLoadError = isFontResourceError(type, text, locationUrl);
|
|
101073
101081
|
const isResourceLoadError = type === "error" && text.startsWith("Failed to load resource") && !isFontLoadError;
|
|
101074
101082
|
const prefix = isResourceLoadError ? "[non-blocking]" : type === "error" ? "[Browser:ERROR]" : type === "warn" ? "[Browser:WARN]" : "[Browser]";
|
|
101075
101083
|
if (!isFontLoadError) {
|
|
@@ -105758,7 +105766,7 @@ var serve = (options, listeningListener) => {
|
|
|
105758
105766
|
};
|
|
105759
105767
|
|
|
105760
105768
|
// src/services/renderOrchestrator.ts
|
|
105761
|
-
import { join as
|
|
105769
|
+
import { join as join15, dirname as dirname10, resolve as resolve10 } from "path";
|
|
105762
105770
|
import { randomUUID } from "crypto";
|
|
105763
105771
|
import { freemem as freemem2 } from "os";
|
|
105764
105772
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -106118,13 +106126,41 @@ function createFileServer2(options) {
|
|
|
106118
106126
|
|
|
106119
106127
|
// src/services/htmlCompiler.ts
|
|
106120
106128
|
import { readFileSync as readFileSync8, existsSync as existsSync14, mkdirSync as mkdirSync9 } from "fs";
|
|
106121
|
-
import { join as
|
|
106129
|
+
import { join as join14, dirname as dirname9, resolve as resolve9 } from "path";
|
|
106122
106130
|
import postcss from "postcss";
|
|
106123
106131
|
|
|
106132
|
+
// src/utils/paths.ts
|
|
106133
|
+
import { resolve as resolve8, basename as basename2, join as join12, relative as relative2, isAbsolute as isAbsolute2 } from "node:path";
|
|
106134
|
+
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve8(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
106135
|
+
function isPathInside(childPath, parentPath) {
|
|
106136
|
+
const absChild = resolve8(childPath);
|
|
106137
|
+
const absParent = resolve8(parentPath);
|
|
106138
|
+
if (absChild === absParent) return true;
|
|
106139
|
+
const rel = relative2(absParent, absChild);
|
|
106140
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
|
|
106141
|
+
}
|
|
106142
|
+
function toExternalAssetKey(absPath) {
|
|
106143
|
+
if (absPath.startsWith("hf-ext/")) return absPath;
|
|
106144
|
+
let normalised = absPath.replace(/\\/g, "/");
|
|
106145
|
+
normalised = normalised.replace(/^\/\/\?\/UNC\//i, "//");
|
|
106146
|
+
normalised = normalised.replace(/^\/\/\?\//, "");
|
|
106147
|
+
normalised = normalised.replace(/^\/\/([^/]+)\//, "unc/$1/");
|
|
106148
|
+
normalised = normalised.replace(/^\/+/, "");
|
|
106149
|
+
normalised = normalised.replace(/^([A-Za-z]):\/?/, "$1/");
|
|
106150
|
+
return "hf-ext/" + normalised;
|
|
106151
|
+
}
|
|
106152
|
+
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
106153
|
+
const absoluteProjectDir = resolve8(projectDir);
|
|
106154
|
+
const projectName = basename2(absoluteProjectDir);
|
|
106155
|
+
const resolvedOutputPath = outputPath ?? join12(rendersDir, `${projectName}.mp4`);
|
|
106156
|
+
const absoluteOutputPath = resolve8(resolvedOutputPath);
|
|
106157
|
+
return { absoluteProjectDir, absoluteOutputPath };
|
|
106158
|
+
}
|
|
106159
|
+
|
|
106124
106160
|
// src/services/deterministicFonts.ts
|
|
106125
106161
|
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
|
|
106126
106162
|
import { homedir as homedir2 } from "node:os";
|
|
106127
|
-
import { join as
|
|
106163
|
+
import { join as join13 } from "node:path";
|
|
106128
106164
|
|
|
106129
106165
|
// src/services/fontData.generated.ts
|
|
106130
106166
|
var EMBEDDED_FONT_DATA = /* @__PURE__ */ new Map([
|
|
@@ -106402,20 +106438,20 @@ function warnUnresolvedFonts(unresolved) {
|
|
|
106402
106438
|
Docs: https://hyperframes.heygen.com/docs/fonts`
|
|
106403
106439
|
);
|
|
106404
106440
|
}
|
|
106405
|
-
var GOOGLE_FONTS_CACHE_DIR =
|
|
106441
|
+
var GOOGLE_FONTS_CACHE_DIR = join13(homedir2(), ".cache", "hyperframes", "fonts");
|
|
106406
106442
|
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";
|
|
106407
106443
|
function fontSlug(familyName) {
|
|
106408
106444
|
return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
106409
106445
|
}
|
|
106410
106446
|
function fontCacheDir(slug) {
|
|
106411
|
-
const dir =
|
|
106447
|
+
const dir = join13(GOOGLE_FONTS_CACHE_DIR, slug);
|
|
106412
106448
|
if (!existsSync13(dir)) {
|
|
106413
106449
|
mkdirSync8(dir, { recursive: true });
|
|
106414
106450
|
}
|
|
106415
106451
|
return dir;
|
|
106416
106452
|
}
|
|
106417
106453
|
function cachedWoff2Path(slug, weight, style) {
|
|
106418
|
-
return
|
|
106454
|
+
return join13(fontCacheDir(slug), `${weight}-${style}.woff2`);
|
|
106419
106455
|
}
|
|
106420
106456
|
async function fetchGoogleFont(familyName) {
|
|
106421
106457
|
const slug = fontSlug(familyName);
|
|
@@ -106517,7 +106553,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
|
|
|
106517
106553
|
return { duration: 0, resolvedPath: src };
|
|
106518
106554
|
}
|
|
106519
106555
|
} else if (!filePath.startsWith("/")) {
|
|
106520
|
-
filePath =
|
|
106556
|
+
filePath = join14(baseDir, filePath);
|
|
106521
106557
|
}
|
|
106522
106558
|
if (!existsSync14(filePath)) {
|
|
106523
106559
|
return { duration: 0, resolvedPath: filePath };
|
|
@@ -106583,7 +106619,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
106583
106619
|
const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
|
|
106584
106620
|
const absoluteStart = parentOffset + elStart;
|
|
106585
106621
|
const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
|
|
106586
|
-
const filePath =
|
|
106622
|
+
const filePath = resolve9(projectDir, srcPath);
|
|
106587
106623
|
if (visited.has(filePath)) {
|
|
106588
106624
|
continue;
|
|
106589
106625
|
}
|
|
@@ -106783,7 +106819,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
106783
106819
|
if (!srcPath) continue;
|
|
106784
106820
|
let compHtml = subCompositions.get(srcPath) || null;
|
|
106785
106821
|
if (!compHtml) {
|
|
106786
|
-
const filePath =
|
|
106822
|
+
const filePath = resolve9(projectDir, srcPath);
|
|
106787
106823
|
if (existsSync14(filePath)) {
|
|
106788
106824
|
compHtml = readFileSync8(filePath, "utf-8");
|
|
106789
106825
|
}
|
|
@@ -106996,7 +107032,7 @@ ${safeText}
|
|
|
106996
107032
|
return result;
|
|
106997
107033
|
}
|
|
106998
107034
|
function collectExternalAssets(html, projectDir) {
|
|
106999
|
-
const absProjectDir =
|
|
107035
|
+
const absProjectDir = resolve9(projectDir);
|
|
107000
107036
|
const externalAssets = /* @__PURE__ */ new Map();
|
|
107001
107037
|
const CSS_URL_RE2 = /\burl\(\s*(["']?)([^)"']+)\1\s*\)/g;
|
|
107002
107038
|
function processPath(rawPath) {
|
|
@@ -107004,12 +107040,12 @@ function collectExternalAssets(html, projectDir) {
|
|
|
107004
107040
|
if (!trimmed || trimmed.startsWith("/") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("//") || trimmed.startsWith("data:") || trimmed.startsWith("#")) {
|
|
107005
107041
|
return null;
|
|
107006
107042
|
}
|
|
107007
|
-
const absPath =
|
|
107008
|
-
if (
|
|
107043
|
+
const absPath = resolve9(absProjectDir, trimmed);
|
|
107044
|
+
if (isPathInside(absPath, absProjectDir)) {
|
|
107009
107045
|
return null;
|
|
107010
107046
|
}
|
|
107011
107047
|
if (!existsSync14(absPath)) return null;
|
|
107012
|
-
const safeKey =
|
|
107048
|
+
const safeKey = toExternalAssetKey(absPath);
|
|
107013
107049
|
externalAssets.set(safeKey, absPath);
|
|
107014
107050
|
return safeKey;
|
|
107015
107051
|
}
|
|
@@ -107081,7 +107117,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
107081
107117
|
const audios = dedupeElementsById([...mainAudios, ...subAudios]);
|
|
107082
107118
|
for (const video of videos) {
|
|
107083
107119
|
if (isHttpUrl(video.src)) continue;
|
|
107084
|
-
const videoPath =
|
|
107120
|
+
const videoPath = resolve9(projectDir, video.src);
|
|
107085
107121
|
const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
|
|
107086
107122
|
Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
|
|
107087
107123
|
if (analysis.isProblematic) {
|
|
@@ -107308,17 +107344,17 @@ function installDebugLogger(logPath, log = defaultLogger) {
|
|
|
107308
107344
|
};
|
|
107309
107345
|
}
|
|
107310
107346
|
function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
107311
|
-
const compileDir =
|
|
107347
|
+
const compileDir = join15(workDir, "compiled");
|
|
107312
107348
|
mkdirSync10(compileDir, { recursive: true });
|
|
107313
|
-
writeFileSync4(
|
|
107349
|
+
writeFileSync4(join15(compileDir, "index.html"), compiled.html, "utf-8");
|
|
107314
107350
|
for (const [srcPath, html] of compiled.subCompositions) {
|
|
107315
|
-
const outPath =
|
|
107351
|
+
const outPath = join15(compileDir, srcPath);
|
|
107316
107352
|
mkdirSync10(dirname10(outPath), { recursive: true });
|
|
107317
107353
|
writeFileSync4(outPath, html, "utf-8");
|
|
107318
107354
|
}
|
|
107319
107355
|
for (const [relativePath, absolutePath] of compiled.externalAssets) {
|
|
107320
|
-
const outPath =
|
|
107321
|
-
if (!outPath
|
|
107356
|
+
const outPath = resolve10(join15(compileDir, relativePath));
|
|
107357
|
+
if (!isPathInside(outPath, compileDir)) {
|
|
107322
107358
|
console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
|
|
107323
107359
|
continue;
|
|
107324
107360
|
}
|
|
@@ -107346,7 +107382,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
|
107346
107382
|
})),
|
|
107347
107383
|
subCompositions: Array.from(compiled.subCompositions.keys())
|
|
107348
107384
|
};
|
|
107349
|
-
writeFileSync4(
|
|
107385
|
+
writeFileSync4(join15(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
|
|
107350
107386
|
}
|
|
107351
107387
|
}
|
|
107352
107388
|
function createRenderJob(config2) {
|
|
@@ -107390,9 +107426,9 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
|
|
|
107390
107426
|
}
|
|
107391
107427
|
async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
|
|
107392
107428
|
const moduleDir = dirname10(fileURLToPath3(import.meta.url));
|
|
107393
|
-
const producerRoot = process.env.PRODUCER_RENDERS_DIR ?
|
|
107394
|
-
const debugDir =
|
|
107395
|
-
const workDir = job.config.debug ?
|
|
107429
|
+
const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve10(process.env.PRODUCER_RENDERS_DIR, "..") : resolve10(moduleDir, "../..");
|
|
107430
|
+
const debugDir = join15(producerRoot, ".debug");
|
|
107431
|
+
const workDir = job.config.debug ? join15(debugDir, job.id) : join15(dirname10(outputPath), `work-${job.id}`);
|
|
107396
107432
|
const pipelineStart = Date.now();
|
|
107397
107433
|
const log = job.config.logger ?? defaultLogger;
|
|
107398
107434
|
let fileServer = null;
|
|
@@ -107400,7 +107436,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107400
107436
|
let lastBrowserConsole = [];
|
|
107401
107437
|
let restoreLogger = null;
|
|
107402
107438
|
const perfStages = {};
|
|
107403
|
-
const perfOutputPath =
|
|
107439
|
+
const perfOutputPath = join15(workDir, "perf-summary.json");
|
|
107404
107440
|
const cfg = { ...job.config.producerConfig ?? resolveConfig() };
|
|
107405
107441
|
const outputFormat = job.config.format ?? "mp4";
|
|
107406
107442
|
const isWebm = outputFormat === "webm";
|
|
@@ -107422,19 +107458,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107422
107458
|
assertNotAborted();
|
|
107423
107459
|
if (!existsSync15(workDir)) mkdirSync10(workDir, { recursive: true });
|
|
107424
107460
|
if (job.config.debug) {
|
|
107425
|
-
const logPath =
|
|
107461
|
+
const logPath = join15(workDir, "render.log");
|
|
107426
107462
|
restoreLogger = installDebugLogger(logPath, log);
|
|
107427
107463
|
}
|
|
107428
107464
|
const entryFile = job.config.entryFile || "index.html";
|
|
107429
|
-
let htmlPath =
|
|
107465
|
+
let htmlPath = join15(projectDir, entryFile);
|
|
107430
107466
|
if (!existsSync15(htmlPath)) {
|
|
107431
107467
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
107432
107468
|
}
|
|
107433
107469
|
assertNotAborted();
|
|
107434
107470
|
const rawEntry = readFileSync9(htmlPath, "utf-8");
|
|
107435
107471
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
107436
|
-
const wrapperPath =
|
|
107437
|
-
const projectIndexPath =
|
|
107472
|
+
const wrapperPath = join15(workDir, "standalone-entry.html");
|
|
107473
|
+
const projectIndexPath = join15(projectDir, "index.html");
|
|
107438
107474
|
if (!existsSync15(projectIndexPath)) {
|
|
107439
107475
|
throw new Error(
|
|
107440
107476
|
`Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
|
|
@@ -107458,7 +107494,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107458
107494
|
const stage1Start = Date.now();
|
|
107459
107495
|
updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
|
|
107460
107496
|
const compileStart = Date.now();
|
|
107461
|
-
let compiled = await compileForRender(projectDir, htmlPath,
|
|
107497
|
+
let compiled = await compileForRender(projectDir, htmlPath, join15(workDir, "downloads"));
|
|
107462
107498
|
assertNotAborted();
|
|
107463
107499
|
perfStages.compileOnlyMs = Date.now() - compileStart;
|
|
107464
107500
|
writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
|
|
@@ -107487,7 +107523,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107487
107523
|
reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
|
|
107488
107524
|
fileServer = await createFileServer2({
|
|
107489
107525
|
projectDir,
|
|
107490
|
-
compiledDir:
|
|
107526
|
+
compiledDir: join15(workDir, "compiled"),
|
|
107491
107527
|
port: 0
|
|
107492
107528
|
});
|
|
107493
107529
|
assertNotAborted();
|
|
@@ -107500,7 +107536,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107500
107536
|
};
|
|
107501
107537
|
probeSession = await createCaptureSession(
|
|
107502
107538
|
fileServer.url,
|
|
107503
|
-
|
|
107539
|
+
join15(workDir, "probe"),
|
|
107504
107540
|
captureOpts,
|
|
107505
107541
|
null,
|
|
107506
107542
|
cfg
|
|
@@ -107532,7 +107568,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107532
107568
|
compiled,
|
|
107533
107569
|
resolutions,
|
|
107534
107570
|
projectDir,
|
|
107535
|
-
|
|
107571
|
+
join15(workDir, "downloads")
|
|
107536
107572
|
);
|
|
107537
107573
|
assertNotAborted();
|
|
107538
107574
|
composition.videos = compiled.videos;
|
|
@@ -107667,12 +107703,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107667
107703
|
const stage2Start = Date.now();
|
|
107668
107704
|
updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
|
|
107669
107705
|
let frameLookup = null;
|
|
107670
|
-
const compiledDir =
|
|
107706
|
+
const compiledDir = join15(workDir, "compiled");
|
|
107671
107707
|
if (composition.videos.length > 0) {
|
|
107672
107708
|
const extractionResult = await extractAllVideoFrames(
|
|
107673
107709
|
composition.videos,
|
|
107674
107710
|
projectDir,
|
|
107675
|
-
{ fps: job.config.fps, outputDir:
|
|
107711
|
+
{ fps: job.config.fps, outputDir: join15(workDir, "video-frames") },
|
|
107676
107712
|
abortSignal,
|
|
107677
107713
|
void 0,
|
|
107678
107714
|
compiledDir
|
|
@@ -107706,13 +107742,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107706
107742
|
}
|
|
107707
107743
|
const stage3Start = Date.now();
|
|
107708
107744
|
updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
|
|
107709
|
-
const audioOutputPath =
|
|
107745
|
+
const audioOutputPath = join15(workDir, "audio.aac");
|
|
107710
107746
|
let hasAudio = false;
|
|
107711
107747
|
if (composition.audios.length > 0) {
|
|
107712
107748
|
const audioResult = await processCompositionAudio(
|
|
107713
107749
|
composition.audios,
|
|
107714
107750
|
projectDir,
|
|
107715
|
-
|
|
107751
|
+
join15(workDir, "audio-work"),
|
|
107716
107752
|
audioOutputPath,
|
|
107717
107753
|
job.duration,
|
|
107718
107754
|
abortSignal,
|
|
@@ -107730,12 +107766,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107730
107766
|
if (!fileServer) {
|
|
107731
107767
|
fileServer = await createFileServer2({
|
|
107732
107768
|
projectDir,
|
|
107733
|
-
compiledDir:
|
|
107769
|
+
compiledDir: join15(workDir, "compiled"),
|
|
107734
107770
|
port: 0
|
|
107735
107771
|
});
|
|
107736
107772
|
assertNotAborted();
|
|
107737
107773
|
}
|
|
107738
|
-
const framesDir =
|
|
107774
|
+
const framesDir = join15(workDir, "captured-frames");
|
|
107739
107775
|
if (!existsSync15(framesDir)) mkdirSync10(framesDir, { recursive: true });
|
|
107740
107776
|
const captureOptions = {
|
|
107741
107777
|
width,
|
|
@@ -107747,7 +107783,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
107747
107783
|
const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
|
|
107748
107784
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
107749
107785
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
107750
|
-
const videoOnlyPath =
|
|
107786
|
+
const videoOnlyPath = join15(workDir, `video-only${videoExt}`);
|
|
107751
107787
|
const preset = getEncoderPreset(job.config.quality, outputFormat);
|
|
107752
107788
|
const effectiveQuality = job.config.crf ?? preset.quality;
|
|
107753
107789
|
const effectiveBitrate = job.config.videoBitrate;
|
|
@@ -108023,7 +108059,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
108023
108059
|
}
|
|
108024
108060
|
if (job.config.debug) {
|
|
108025
108061
|
if (existsSync15(outputPath)) {
|
|
108026
|
-
const debugOutput =
|
|
108062
|
+
const debugOutput = join15(workDir, `output${videoExt}`);
|
|
108027
108063
|
copyFileSync2(outputPath, debugOutput);
|
|
108028
108064
|
}
|
|
108029
108065
|
} else {
|
|
@@ -108282,7 +108318,7 @@ var streamSSE = (c, cb, onError) => {
|
|
|
108282
108318
|
|
|
108283
108319
|
// src/services/hyperframeLint.ts
|
|
108284
108320
|
import { existsSync as existsSync16, readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
|
|
108285
|
-
import { resolve as
|
|
108321
|
+
import { resolve as resolve11, join as join16 } from "node:path";
|
|
108286
108322
|
function isStringRecord(value) {
|
|
108287
108323
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
108288
108324
|
return false;
|
|
@@ -108309,7 +108345,7 @@ function pickEntryFile(files, preferredEntryFile) {
|
|
|
108309
108345
|
return null;
|
|
108310
108346
|
}
|
|
108311
108347
|
function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
108312
|
-
const absProjectDir =
|
|
108348
|
+
const absProjectDir = resolve11(projectDir);
|
|
108313
108349
|
if (!existsSync16(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
|
|
108314
108350
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
108315
108351
|
}
|
|
@@ -108317,7 +108353,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
108317
108353
|
(value) => typeof value === "string" && value.trim().length > 0
|
|
108318
108354
|
);
|
|
108319
108355
|
for (const entryFile of entryCandidates) {
|
|
108320
|
-
const absoluteEntryPath =
|
|
108356
|
+
const absoluteEntryPath = resolve11(absProjectDir, entryFile);
|
|
108321
108357
|
if (!absoluteEntryPath.startsWith(absProjectDir)) {
|
|
108322
108358
|
return { error: `Entry file must stay inside project directory: ${entryFile}` };
|
|
108323
108359
|
}
|
|
@@ -108330,7 +108366,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
108330
108366
|
}
|
|
108331
108367
|
}
|
|
108332
108368
|
return {
|
|
108333
|
-
error: `No HTML entry file found in project directory: ${
|
|
108369
|
+
error: `No HTML entry file found in project directory: ${join16(absProjectDir, preferredEntryFile || "index.html")}`
|
|
108334
108370
|
};
|
|
108335
108371
|
}
|
|
108336
108372
|
function prepareHyperframeLintBody(body) {
|
|
@@ -108370,17 +108406,6 @@ function runHyperframeLint(prepared) {
|
|
|
108370
108406
|
return lintHyperframeHtml(prepared.html, { filePath: prepared.entryFile });
|
|
108371
108407
|
}
|
|
108372
108408
|
|
|
108373
|
-
// src/utils/paths.ts
|
|
108374
|
-
import { resolve as resolve11, basename as basename2, join as join16 } from "node:path";
|
|
108375
|
-
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve11(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
108376
|
-
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
108377
|
-
const absoluteProjectDir = resolve11(projectDir);
|
|
108378
|
-
const projectName = basename2(absoluteProjectDir);
|
|
108379
|
-
const resolvedOutputPath = outputPath ?? join16(rendersDir, `${projectName}.mp4`);
|
|
108380
|
-
const absoluteOutputPath = resolve11(resolvedOutputPath);
|
|
108381
|
-
return { absoluteProjectDir, absoluteOutputPath };
|
|
108382
|
-
}
|
|
108383
|
-
|
|
108384
108409
|
// src/utils/semaphore.ts
|
|
108385
108410
|
var Semaphore = class {
|
|
108386
108411
|
constructor(maxConcurrent) {
|