hyperframes 0.5.0-alpha.1 → 0.5.0-alpha.3
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/cli.js
CHANGED
|
@@ -54,7 +54,7 @@ var VERSION;
|
|
|
54
54
|
var init_version = __esm({
|
|
55
55
|
"src/version.ts"() {
|
|
56
56
|
"use strict";
|
|
57
|
-
VERSION = true ? "0.5.0-alpha.
|
|
57
|
+
VERSION = true ? "0.5.0-alpha.3" : "0.0.0-dev";
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
|
|
@@ -5723,24 +5723,6 @@ var init_composition = __esm({
|
|
|
5723
5723
|
}
|
|
5724
5724
|
return findings;
|
|
5725
5725
|
},
|
|
5726
|
-
// root_composition_missing_data_duration
|
|
5727
|
-
({ rootTag }) => {
|
|
5728
|
-
const findings = [];
|
|
5729
|
-
if (!rootTag) return findings;
|
|
5730
|
-
const compId = readAttr(rootTag.raw, "data-composition-id");
|
|
5731
|
-
if (!compId) return findings;
|
|
5732
|
-
const hasDuration = readAttr(rootTag.raw, "data-duration") !== null;
|
|
5733
|
-
if (!hasDuration) {
|
|
5734
|
-
findings.push({
|
|
5735
|
-
code: "root_composition_missing_data_duration",
|
|
5736
|
-
severity: "warning",
|
|
5737
|
-
message: `Root composition "${compId}" is missing data-duration. Without an explicit duration, the runtime may infer Infinity for compositions with repeating animations, causing playback issues.`,
|
|
5738
|
-
fixHint: 'Add data-duration="X" to the root composition element, where X is the total duration in seconds.',
|
|
5739
|
-
snippet: truncateSnippet(rootTag.raw)
|
|
5740
|
-
});
|
|
5741
|
-
}
|
|
5742
|
-
return findings;
|
|
5743
|
-
},
|
|
5744
5726
|
// standalone_composition_wrapped_in_template
|
|
5745
5727
|
({ rawSource, options }) => {
|
|
5746
5728
|
const findings = [];
|
|
@@ -9868,8 +9850,8 @@ function flushSync() {
|
|
|
9868
9850
|
eventQueue = [];
|
|
9869
9851
|
const payload = JSON.stringify({ api_key: POSTHOG_API_KEY, batch });
|
|
9870
9852
|
try {
|
|
9871
|
-
const { spawn:
|
|
9872
|
-
const child =
|
|
9853
|
+
const { spawn: spawn14 } = __require("child_process");
|
|
9854
|
+
const child = spawn14(
|
|
9873
9855
|
process.execPath,
|
|
9874
9856
|
[
|
|
9875
9857
|
"-e",
|
|
@@ -10521,9 +10503,9 @@ function findWavDataChunk(buf) {
|
|
|
10521
10503
|
return null;
|
|
10522
10504
|
}
|
|
10523
10505
|
function detectSpeechOnset(wavPath) {
|
|
10524
|
-
const
|
|
10506
|
+
const SAMPLE_RATE2 = 16e3;
|
|
10525
10507
|
const WINDOW_SECONDS = 0.5;
|
|
10526
|
-
const WINDOW_SAMPLES =
|
|
10508
|
+
const WINDOW_SAMPLES = SAMPLE_RATE2 * WINDOW_SECONDS;
|
|
10527
10509
|
const SUSTAINED_WINDOWS = 3;
|
|
10528
10510
|
const SILENCE_THRESHOLD_RATIO = 0.6;
|
|
10529
10511
|
const MIN_INTRO_SECONDS = 3;
|
|
@@ -10802,14 +10784,14 @@ function lintProject(project) {
|
|
|
10802
10784
|
totalErrors += rootResult.errorCount;
|
|
10803
10785
|
totalWarnings += rootResult.warningCount;
|
|
10804
10786
|
totalInfos += rootResult.infoCount;
|
|
10805
|
-
const allHtmlSources = [rootHtml];
|
|
10787
|
+
const allHtmlSources = [{ html: rootHtml }];
|
|
10806
10788
|
const compositionsDir = resolve5(project.dir, "compositions");
|
|
10807
10789
|
if (existsSync7(compositionsDir)) {
|
|
10808
10790
|
const files = readdirSync2(compositionsDir).filter((f3) => f3.endsWith(".html"));
|
|
10809
10791
|
for (const file of files) {
|
|
10810
10792
|
const filePath = join9(compositionsDir, file);
|
|
10811
10793
|
const html = readFileSync7(filePath, "utf-8");
|
|
10812
|
-
allHtmlSources.push(html);
|
|
10794
|
+
allHtmlSources.push({ html, compSrcPath: `compositions/${file}` });
|
|
10813
10795
|
const result = lintHyperframeHtml(html, { filePath, isSubComposition: true });
|
|
10814
10796
|
results.push({ file: `compositions/${file}`, result });
|
|
10815
10797
|
totalErrors += result.errorCount;
|
|
@@ -10852,7 +10834,7 @@ function lintProjectAudioFiles(projectDir, htmlSources) {
|
|
|
10852
10834
|
return findings;
|
|
10853
10835
|
}
|
|
10854
10836
|
if (audioFiles.length === 0) return findings;
|
|
10855
|
-
const hasAudioElement = htmlSources.some((html) => /<audio\b/i.test(html));
|
|
10837
|
+
const hasAudioElement = htmlSources.some(({ html }) => /<audio\b/i.test(html));
|
|
10856
10838
|
if (!hasAudioElement) {
|
|
10857
10839
|
findings.push({
|
|
10858
10840
|
code: "audio_file_without_element",
|
|
@@ -10867,13 +10849,14 @@ function lintAudioSrcNotFound(projectDir, htmlSources) {
|
|
|
10867
10849
|
const findings = [];
|
|
10868
10850
|
const audioSrcRe = /<audio\b[^>]*\bsrc\s*=\s*["']([^"']+)["'][^>]*>/gi;
|
|
10869
10851
|
const missingSrcs = [];
|
|
10870
|
-
for (const html of htmlSources) {
|
|
10852
|
+
for (const { html, compSrcPath } of htmlSources) {
|
|
10871
10853
|
let match;
|
|
10872
10854
|
while ((match = audioSrcRe.exec(html)) !== null) {
|
|
10873
10855
|
const src = match[1];
|
|
10874
10856
|
if (/^(https?:|data:|blob:)/i.test(src)) continue;
|
|
10875
10857
|
if (/^__[A-Z_]+__$/.test(src)) continue;
|
|
10876
|
-
const
|
|
10858
|
+
const rootRelative = compSrcPath ? rewriteAssetPath(compSrcPath, src) : src;
|
|
10859
|
+
const resolved = resolve5(projectDir, rootRelative);
|
|
10877
10860
|
if (!existsSync7(resolved)) {
|
|
10878
10861
|
missingSrcs.push(src);
|
|
10879
10862
|
}
|
|
@@ -10922,7 +10905,7 @@ function lintDuplicateAudioTracks(htmlSources) {
|
|
|
10922
10905
|
}
|
|
10923
10906
|
const tracks = [];
|
|
10924
10907
|
const seen = /* @__PURE__ */ new Set();
|
|
10925
|
-
for (const html of htmlSources) {
|
|
10908
|
+
for (const { html } of htmlSources) {
|
|
10926
10909
|
const audioTagRe = /<audio\b[^>]*>/gi;
|
|
10927
10910
|
let match;
|
|
10928
10911
|
while ((match = audioTagRe.exec(html)) !== null) {
|
|
@@ -10966,6 +10949,7 @@ var init_lintProject = __esm({
|
|
|
10966
10949
|
"src/utils/lintProject.ts"() {
|
|
10967
10950
|
"use strict";
|
|
10968
10951
|
init_lint();
|
|
10952
|
+
init_src();
|
|
10969
10953
|
AUDIO_EXTENSIONS2 = /* @__PURE__ */ new Set([".mp3", ".wav", ".aac", ".ogg", ".m4a", ".flac", ".opus"]);
|
|
10970
10954
|
}
|
|
10971
10955
|
});
|
|
@@ -11418,11 +11402,138 @@ var init_projects = __esm({
|
|
|
11418
11402
|
}
|
|
11419
11403
|
});
|
|
11420
11404
|
|
|
11405
|
+
// ../core/src/studio-api/helpers/mime.ts
|
|
11406
|
+
function getMimeType(path2) {
|
|
11407
|
+
const ext = path2.slice(path2.lastIndexOf(".")).toLowerCase();
|
|
11408
|
+
return MIME_TYPES[ext] || "application/octet-stream";
|
|
11409
|
+
}
|
|
11410
|
+
function isAudioFile2(name) {
|
|
11411
|
+
return (getMimeType(name) ?? "").startsWith("audio/");
|
|
11412
|
+
}
|
|
11413
|
+
var MIME_TYPES;
|
|
11414
|
+
var init_mime = __esm({
|
|
11415
|
+
"../core/src/studio-api/helpers/mime.ts"() {
|
|
11416
|
+
"use strict";
|
|
11417
|
+
MIME_TYPES = {
|
|
11418
|
+
".html": "text/html",
|
|
11419
|
+
".css": "text/css",
|
|
11420
|
+
".js": "text/javascript",
|
|
11421
|
+
".mjs": "text/javascript",
|
|
11422
|
+
".json": "application/json",
|
|
11423
|
+
".svg": "image/svg+xml",
|
|
11424
|
+
".png": "image/png",
|
|
11425
|
+
".jpg": "image/jpeg",
|
|
11426
|
+
".jpeg": "image/jpeg",
|
|
11427
|
+
".gif": "image/gif",
|
|
11428
|
+
".webp": "image/webp",
|
|
11429
|
+
".ico": "image/x-icon",
|
|
11430
|
+
".mp4": "video/mp4",
|
|
11431
|
+
".mov": "video/quicktime",
|
|
11432
|
+
".webm": "video/webm",
|
|
11433
|
+
".mp3": "audio/mpeg",
|
|
11434
|
+
".wav": "audio/wav",
|
|
11435
|
+
".ogg": "audio/ogg",
|
|
11436
|
+
".m4a": "audio/mp4",
|
|
11437
|
+
".aac": "audio/aac",
|
|
11438
|
+
".flac": "audio/flac",
|
|
11439
|
+
".opus": "audio/ogg",
|
|
11440
|
+
".woff": "font/woff",
|
|
11441
|
+
".woff2": "font/woff2",
|
|
11442
|
+
".ttf": "font/ttf",
|
|
11443
|
+
".otf": "font/otf",
|
|
11444
|
+
".txt": "text/plain",
|
|
11445
|
+
".md": "text/markdown"
|
|
11446
|
+
};
|
|
11447
|
+
}
|
|
11448
|
+
});
|
|
11449
|
+
|
|
11450
|
+
// ../core/src/studio-api/helpers/waveform.ts
|
|
11451
|
+
import { spawn as spawn2 } from "child_process";
|
|
11452
|
+
import { existsSync as existsSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
|
|
11453
|
+
import { join as join11 } from "path";
|
|
11454
|
+
function buildWaveformCacheKey(assetPath) {
|
|
11455
|
+
return `${WAVEFORM_CACHE_VERSION}_${assetPath.replace(/[/\\]/g, "_")}.json`;
|
|
11456
|
+
}
|
|
11457
|
+
function computePeaks(floats, count) {
|
|
11458
|
+
const step = floats.length / count;
|
|
11459
|
+
const peaks = [];
|
|
11460
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
11461
|
+
const start = Math.floor(i2 * step);
|
|
11462
|
+
const end = Math.min(Math.floor((i2 + 1) * step), floats.length);
|
|
11463
|
+
let max = 0;
|
|
11464
|
+
for (let j2 = start; j2 < end; j2++) {
|
|
11465
|
+
const abs = Math.abs(floats[j2] ?? 0);
|
|
11466
|
+
if (abs > max) max = abs;
|
|
11467
|
+
}
|
|
11468
|
+
peaks.push(max);
|
|
11469
|
+
}
|
|
11470
|
+
const maxPeak = Math.max(...peaks, 1e-3);
|
|
11471
|
+
return peaks.map((p) => p / maxPeak);
|
|
11472
|
+
}
|
|
11473
|
+
function decodeAudioPeaks(audioPath) {
|
|
11474
|
+
return new Promise((resolve39, reject) => {
|
|
11475
|
+
const proc = spawn2(
|
|
11476
|
+
"ffmpeg",
|
|
11477
|
+
[
|
|
11478
|
+
"-i",
|
|
11479
|
+
audioPath,
|
|
11480
|
+
"-af",
|
|
11481
|
+
"atrim=start_sample=1152",
|
|
11482
|
+
"-f",
|
|
11483
|
+
"f32le",
|
|
11484
|
+
"-ac",
|
|
11485
|
+
"1",
|
|
11486
|
+
"-ar",
|
|
11487
|
+
String(SAMPLE_RATE),
|
|
11488
|
+
"-vn",
|
|
11489
|
+
"pipe:1"
|
|
11490
|
+
],
|
|
11491
|
+
{ stdio: ["ignore", "pipe", "ignore"] }
|
|
11492
|
+
);
|
|
11493
|
+
const chunks = [];
|
|
11494
|
+
proc.stdout?.on("data", (chunk) => chunks.push(chunk));
|
|
11495
|
+
proc.on("close", (code) => {
|
|
11496
|
+
if (code !== 0 && chunks.length === 0) {
|
|
11497
|
+
reject(new Error(`ffmpeg exited with code ${code}`));
|
|
11498
|
+
return;
|
|
11499
|
+
}
|
|
11500
|
+
const buf = Buffer.concat(chunks);
|
|
11501
|
+
const numSamples = Math.floor(buf.length / 4);
|
|
11502
|
+
if (numSamples === 0) {
|
|
11503
|
+
reject(new Error("ffmpeg produced no audio samples"));
|
|
11504
|
+
return;
|
|
11505
|
+
}
|
|
11506
|
+
const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + numSamples * 4);
|
|
11507
|
+
resolve39(computePeaks(new Float32Array(ab), PEAK_COUNT));
|
|
11508
|
+
});
|
|
11509
|
+
proc.on("error", reject);
|
|
11510
|
+
});
|
|
11511
|
+
}
|
|
11512
|
+
async function generateWaveformCache(projectDir, assetPath) {
|
|
11513
|
+
const audioPath = join11(projectDir, assetPath);
|
|
11514
|
+
if (!existsSync9(audioPath)) return;
|
|
11515
|
+
const cacheDir = join11(projectDir, ".waveform-cache");
|
|
11516
|
+
const cachePath2 = join11(cacheDir, buildWaveformCacheKey(assetPath));
|
|
11517
|
+
if (existsSync9(cachePath2)) return;
|
|
11518
|
+
const peaks = await decodeAudioPeaks(audioPath);
|
|
11519
|
+
mkdirSync5(cacheDir, { recursive: true });
|
|
11520
|
+
writeFileSync5(cachePath2, JSON.stringify(peaks));
|
|
11521
|
+
}
|
|
11522
|
+
var SAMPLE_RATE, PEAK_COUNT, WAVEFORM_CACHE_VERSION;
|
|
11523
|
+
var init_waveform = __esm({
|
|
11524
|
+
"../core/src/studio-api/helpers/waveform.ts"() {
|
|
11525
|
+
"use strict";
|
|
11526
|
+
SAMPLE_RATE = 4e3;
|
|
11527
|
+
PEAK_COUNT = 4e3;
|
|
11528
|
+
WAVEFORM_CACHE_VERSION = "v2";
|
|
11529
|
+
}
|
|
11530
|
+
});
|
|
11531
|
+
|
|
11421
11532
|
// ../core/src/studio-api/helpers/mediaValidation.ts
|
|
11422
11533
|
import { spawnSync } from "child_process";
|
|
11423
|
-
import { mkdtempSync, rmSync as rmSync2, writeFileSync as
|
|
11534
|
+
import { mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
11424
11535
|
import { tmpdir as tmpdir2 } from "os";
|
|
11425
|
-
import { basename, join as
|
|
11536
|
+
import { basename, join as join12 } from "path";
|
|
11426
11537
|
function validateUploadedMedia(filePath, runner = spawnSync) {
|
|
11427
11538
|
const isVideo2 = VIDEO_EXT.test(filePath);
|
|
11428
11539
|
const isAudio = AUDIO_EXT.test(filePath);
|
|
@@ -11461,10 +11572,10 @@ function validateUploadedMedia(filePath, runner = spawnSync) {
|
|
|
11461
11572
|
}
|
|
11462
11573
|
}
|
|
11463
11574
|
function validateUploadedMediaBuffer(fileName, buffer, runner = spawnSync) {
|
|
11464
|
-
const tempDir = mkdtempSync(
|
|
11465
|
-
const tempPath =
|
|
11575
|
+
const tempDir = mkdtempSync(join12(tmpdir2(), "hyperframes-upload-"));
|
|
11576
|
+
const tempPath = join12(tempDir, basename(fileName));
|
|
11466
11577
|
try {
|
|
11467
|
-
|
|
11578
|
+
writeFileSync6(tempPath, buffer);
|
|
11468
11579
|
return validateUploadedMedia(tempPath, runner);
|
|
11469
11580
|
} finally {
|
|
11470
11581
|
rmSync2(tempDir, { recursive: true, force: true });
|
|
@@ -23317,7 +23428,7 @@ var init_html_classes = __esm({
|
|
|
23317
23428
|
|
|
23318
23429
|
// ../../node_modules/.bun/linkedom@0.18.12/node_modules/linkedom/esm/shared/mime.js
|
|
23319
23430
|
var voidElements2, Mime;
|
|
23320
|
-
var
|
|
23431
|
+
var init_mime2 = __esm({
|
|
23321
23432
|
"../../node_modules/.bun/linkedom@0.18.12/node_modules/linkedom/esm/shared/mime.js"() {
|
|
23322
23433
|
"use strict";
|
|
23323
23434
|
voidElements2 = { test: () => true };
|
|
@@ -23582,7 +23693,7 @@ var init_document = __esm({
|
|
|
23582
23693
|
init_symbols();
|
|
23583
23694
|
init_facades();
|
|
23584
23695
|
init_html_classes();
|
|
23585
|
-
|
|
23696
|
+
init_mime2();
|
|
23586
23697
|
init_utils2();
|
|
23587
23698
|
init_object();
|
|
23588
23699
|
init_non_element_parent_node();
|
|
@@ -24121,17 +24232,17 @@ var init_sourceMutation = __esm({
|
|
|
24121
24232
|
// ../core/src/studio-api/routes/files.ts
|
|
24122
24233
|
import { bodyLimit } from "hono/body-limit";
|
|
24123
24234
|
import {
|
|
24124
|
-
existsSync as
|
|
24235
|
+
existsSync as existsSync10,
|
|
24125
24236
|
readFileSync as readFileSync9,
|
|
24126
|
-
writeFileSync as
|
|
24127
|
-
mkdirSync as
|
|
24237
|
+
writeFileSync as writeFileSync7,
|
|
24238
|
+
mkdirSync as mkdirSync6,
|
|
24128
24239
|
unlinkSync as unlinkSync3,
|
|
24129
24240
|
rmSync as rmSync3,
|
|
24130
24241
|
statSync,
|
|
24131
24242
|
renameSync as renameSync2,
|
|
24132
24243
|
readdirSync as readdirSync4
|
|
24133
24244
|
} from "fs";
|
|
24134
|
-
import { resolve as resolve9, dirname as dirname5, join as
|
|
24245
|
+
import { resolve as resolve9, dirname as dirname5, join as join13 } from "path";
|
|
24135
24246
|
async function resolveProjectFile(c2, adapter2, opts) {
|
|
24136
24247
|
const id = c2.req.param("id");
|
|
24137
24248
|
const project = await adapter2.resolveProject(id);
|
|
@@ -24146,14 +24257,14 @@ async function resolveProjectFile(c2, adapter2, opts) {
|
|
|
24146
24257
|
if (!isSafePath(project.dir, absPath)) {
|
|
24147
24258
|
return { error: c2.json({ error: "forbidden" }, 403) };
|
|
24148
24259
|
}
|
|
24149
|
-
if (opts?.mustExist && !
|
|
24260
|
+
if (opts?.mustExist && !existsSync10(absPath)) {
|
|
24150
24261
|
return { error: c2.json({ error: "not found" }, 404) };
|
|
24151
24262
|
}
|
|
24152
24263
|
return { project, filePath, absPath };
|
|
24153
24264
|
}
|
|
24154
24265
|
function ensureDir(filePath) {
|
|
24155
24266
|
const dir = dirname5(filePath);
|
|
24156
|
-
if (!
|
|
24267
|
+
if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true });
|
|
24157
24268
|
}
|
|
24158
24269
|
function generateCopyPath(projectDir, originalPath) {
|
|
24159
24270
|
const ext = originalPath.includes(".") ? "." + originalPath.split(".").pop() : "";
|
|
@@ -24162,7 +24273,7 @@ function generateCopyPath(projectDir, originalPath) {
|
|
|
24162
24273
|
const cleanBase = copyMatch ? base.slice(0, -copyMatch[0].length) : base;
|
|
24163
24274
|
let num = copyMatch ? copyMatch[1] ? parseInt(copyMatch[1]) + 1 : 2 : 1;
|
|
24164
24275
|
let candidate = num === 1 ? `${cleanBase} (copy)${ext}` : `${cleanBase} (copy ${num})${ext}`;
|
|
24165
|
-
while (
|
|
24276
|
+
while (existsSync10(resolve9(projectDir, candidate))) {
|
|
24166
24277
|
num++;
|
|
24167
24278
|
candidate = `${cleanBase} (copy ${num})${ext}`;
|
|
24168
24279
|
}
|
|
@@ -24171,7 +24282,7 @@ function generateCopyPath(projectDir, originalPath) {
|
|
|
24171
24282
|
function walkFiles(dir, filter2) {
|
|
24172
24283
|
const results = [];
|
|
24173
24284
|
for (const entry of readdirSync4(dir, { withFileTypes: true })) {
|
|
24174
|
-
const full =
|
|
24285
|
+
const full = join13(dir, entry.name);
|
|
24175
24286
|
if (entry.isDirectory()) {
|
|
24176
24287
|
if (entry.name === "node_modules" || entry.name === ".thumbnails" || entry.name === "renders")
|
|
24177
24288
|
continue;
|
|
@@ -24193,7 +24304,7 @@ function updateReferences(projectDir, oldPath, newPath) {
|
|
|
24193
24304
|
if (!content.includes(oldPath)) continue;
|
|
24194
24305
|
const updated = content.split(oldPath).join(newPath);
|
|
24195
24306
|
if (updated !== content) {
|
|
24196
|
-
|
|
24307
|
+
writeFileSync7(file, updated, "utf-8");
|
|
24197
24308
|
updatedCount++;
|
|
24198
24309
|
}
|
|
24199
24310
|
}
|
|
@@ -24211,18 +24322,18 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24211
24322
|
if ("error" in res) return res.error;
|
|
24212
24323
|
ensureDir(res.absPath);
|
|
24213
24324
|
const body = await c2.req.text();
|
|
24214
|
-
|
|
24325
|
+
writeFileSync7(res.absPath, body, "utf-8");
|
|
24215
24326
|
return c2.json({ ok: true });
|
|
24216
24327
|
});
|
|
24217
24328
|
api.post("/projects/:id/files/*", async (c2) => {
|
|
24218
24329
|
const res = await resolveProjectFile(c2, adapter2);
|
|
24219
24330
|
if ("error" in res) return res.error;
|
|
24220
|
-
if (
|
|
24331
|
+
if (existsSync10(res.absPath)) {
|
|
24221
24332
|
return c2.json({ error: "already exists" }, 409);
|
|
24222
24333
|
}
|
|
24223
24334
|
ensureDir(res.absPath);
|
|
24224
24335
|
const body = await c2.req.text().catch(() => "");
|
|
24225
|
-
|
|
24336
|
+
writeFileSync7(res.absPath, body, "utf-8");
|
|
24226
24337
|
return c2.json({ ok: true, path: res.filePath }, 201);
|
|
24227
24338
|
});
|
|
24228
24339
|
api.delete("/projects/:id/files/*", async (c2) => {
|
|
@@ -24250,7 +24361,7 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24250
24361
|
if (!isSafePath(project.dir, absPath)) {
|
|
24251
24362
|
return c2.json({ error: "forbidden" }, 403);
|
|
24252
24363
|
}
|
|
24253
|
-
if (!
|
|
24364
|
+
if (!existsSync10(absPath)) {
|
|
24254
24365
|
return c2.json({ error: "not found" }, 404);
|
|
24255
24366
|
}
|
|
24256
24367
|
const body = await c2.req.json().catch(() => null);
|
|
@@ -24262,7 +24373,7 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24262
24373
|
if (patchedContent === originalContent) {
|
|
24263
24374
|
return c2.json({ ok: true, changed: false, content: originalContent });
|
|
24264
24375
|
}
|
|
24265
|
-
|
|
24376
|
+
writeFileSync7(absPath, patchedContent, "utf-8");
|
|
24266
24377
|
return c2.json({ ok: true, changed: true, content: patchedContent });
|
|
24267
24378
|
});
|
|
24268
24379
|
api.patch("/projects/:id/files/*", async (c2) => {
|
|
@@ -24276,7 +24387,7 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24276
24387
|
if (!isSafePath(res.project.dir, newAbs)) {
|
|
24277
24388
|
return c2.json({ error: "forbidden" }, 403);
|
|
24278
24389
|
}
|
|
24279
|
-
if (
|
|
24390
|
+
if (existsSync10(newAbs)) {
|
|
24280
24391
|
return c2.json({ error: "already exists" }, 409);
|
|
24281
24392
|
}
|
|
24282
24393
|
ensureDir(newAbs);
|
|
@@ -24292,7 +24403,7 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24292
24403
|
return c2.json({ error: "path required" }, 400);
|
|
24293
24404
|
}
|
|
24294
24405
|
const srcAbs = resolve9(project.dir, body.path);
|
|
24295
|
-
if (!isSafePath(project.dir, srcAbs) || !
|
|
24406
|
+
if (!isSafePath(project.dir, srcAbs) || !existsSync10(srcAbs)) {
|
|
24296
24407
|
return c2.json({ error: "not found" }, 404);
|
|
24297
24408
|
}
|
|
24298
24409
|
const copyPath = generateCopyPath(project.dir, body.path);
|
|
@@ -24301,7 +24412,7 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24301
24412
|
return c2.json({ error: "forbidden" }, 403);
|
|
24302
24413
|
}
|
|
24303
24414
|
ensureDir(destAbs);
|
|
24304
|
-
|
|
24415
|
+
writeFileSync7(destAbs, readFileSync9(srcAbs));
|
|
24305
24416
|
return c2.json({ ok: true, path: copyPath }, 201);
|
|
24306
24417
|
});
|
|
24307
24418
|
const MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
|
|
@@ -24317,7 +24428,7 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24317
24428
|
const subDir = c2.req.query("dir") ?? "";
|
|
24318
24429
|
const targetDir = subDir ? resolve9(project.dir, subDir) : project.dir;
|
|
24319
24430
|
if (!isSafePath(project.dir, targetDir)) return c2.json({ error: "forbidden" }, 403);
|
|
24320
|
-
if (subDir && !
|
|
24431
|
+
if (subDir && !existsSync10(targetDir)) mkdirSync6(targetDir, { recursive: true });
|
|
24321
24432
|
const formData = await c2.req.formData();
|
|
24322
24433
|
const uploaded = [];
|
|
24323
24434
|
const skipped = [];
|
|
@@ -24334,12 +24445,12 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24334
24445
|
if (!isSafePath(project.dir, destPath)) continue;
|
|
24335
24446
|
let finalPath = destPath;
|
|
24336
24447
|
let finalName = name;
|
|
24337
|
-
if (
|
|
24448
|
+
if (existsSync10(finalPath)) {
|
|
24338
24449
|
const dotIdx = name.indexOf(".", name.startsWith(".") ? 1 : 0);
|
|
24339
24450
|
const ext = dotIdx > 0 ? name.slice(dotIdx) : "";
|
|
24340
24451
|
const base = dotIdx > 0 ? name.slice(0, dotIdx) : name;
|
|
24341
24452
|
let n = 2;
|
|
24342
|
-
while (n < 1e4 &&
|
|
24453
|
+
while (n < 1e4 && existsSync10(resolve9(targetDir, `${base} (${n})${ext}`))) n++;
|
|
24343
24454
|
if (n >= 1e4) {
|
|
24344
24455
|
skipped.push(name);
|
|
24345
24456
|
continue;
|
|
@@ -24353,8 +24464,13 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24353
24464
|
invalid.push({ name: finalName, reason: validation.reason });
|
|
24354
24465
|
continue;
|
|
24355
24466
|
}
|
|
24356
|
-
|
|
24357
|
-
|
|
24467
|
+
writeFileSync7(finalPath, buffer);
|
|
24468
|
+
const relativePath = subDir ? join13(subDir, finalName) : finalName;
|
|
24469
|
+
uploaded.push(relativePath);
|
|
24470
|
+
if (isAudioFile2(finalName)) {
|
|
24471
|
+
generateWaveformCache(project.dir, relativePath).catch(() => {
|
|
24472
|
+
});
|
|
24473
|
+
}
|
|
24358
24474
|
}
|
|
24359
24475
|
return c2.json({ ok: true, files: uploaded, skipped, invalid }, 201);
|
|
24360
24476
|
}
|
|
@@ -24363,57 +24479,20 @@ function registerFileRoutes(api, adapter2) {
|
|
|
24363
24479
|
var init_files = __esm({
|
|
24364
24480
|
"../core/src/studio-api/routes/files.ts"() {
|
|
24365
24481
|
"use strict";
|
|
24482
|
+
init_mime();
|
|
24483
|
+
init_waveform();
|
|
24366
24484
|
init_mediaValidation();
|
|
24367
24485
|
init_safePath();
|
|
24368
24486
|
init_sourceMutation();
|
|
24369
24487
|
}
|
|
24370
24488
|
});
|
|
24371
24489
|
|
|
24372
|
-
// ../core/src/studio-api/helpers/mime.ts
|
|
24373
|
-
function getMimeType(path2) {
|
|
24374
|
-
const ext = path2.slice(path2.lastIndexOf(".")).toLowerCase();
|
|
24375
|
-
return MIME_TYPES[ext] || "application/octet-stream";
|
|
24376
|
-
}
|
|
24377
|
-
var MIME_TYPES;
|
|
24378
|
-
var init_mime2 = __esm({
|
|
24379
|
-
"../core/src/studio-api/helpers/mime.ts"() {
|
|
24380
|
-
"use strict";
|
|
24381
|
-
MIME_TYPES = {
|
|
24382
|
-
".html": "text/html",
|
|
24383
|
-
".css": "text/css",
|
|
24384
|
-
".js": "text/javascript",
|
|
24385
|
-
".mjs": "text/javascript",
|
|
24386
|
-
".json": "application/json",
|
|
24387
|
-
".svg": "image/svg+xml",
|
|
24388
|
-
".png": "image/png",
|
|
24389
|
-
".jpg": "image/jpeg",
|
|
24390
|
-
".jpeg": "image/jpeg",
|
|
24391
|
-
".gif": "image/gif",
|
|
24392
|
-
".webp": "image/webp",
|
|
24393
|
-
".ico": "image/x-icon",
|
|
24394
|
-
".mp4": "video/mp4",
|
|
24395
|
-
".mov": "video/quicktime",
|
|
24396
|
-
".webm": "video/webm",
|
|
24397
|
-
".mp3": "audio/mpeg",
|
|
24398
|
-
".wav": "audio/wav",
|
|
24399
|
-
".ogg": "audio/ogg",
|
|
24400
|
-
".m4a": "audio/mp4",
|
|
24401
|
-
".woff": "font/woff",
|
|
24402
|
-
".woff2": "font/woff2",
|
|
24403
|
-
".ttf": "font/ttf",
|
|
24404
|
-
".otf": "font/otf",
|
|
24405
|
-
".txt": "text/plain",
|
|
24406
|
-
".md": "text/markdown"
|
|
24407
|
-
};
|
|
24408
|
-
}
|
|
24409
|
-
});
|
|
24410
|
-
|
|
24411
24490
|
// ../core/src/studio-api/helpers/subComposition.ts
|
|
24412
|
-
import { existsSync as
|
|
24413
|
-
import { join as
|
|
24491
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
24492
|
+
import { join as join14 } from "path";
|
|
24414
24493
|
function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref) {
|
|
24415
|
-
const compFile =
|
|
24416
|
-
if (!
|
|
24494
|
+
const compFile = join14(projectDir, compPath);
|
|
24495
|
+
if (!existsSync11(compFile)) return null;
|
|
24417
24496
|
const rawComp = readFileSync10(compFile, "utf-8");
|
|
24418
24497
|
const templateMatch = rawComp.match(/<template[^>]*>([\s\S]*)<\/template>/i);
|
|
24419
24498
|
const content = templateMatch?.[1] ?? rawComp;
|
|
@@ -24440,9 +24519,9 @@ function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref) {
|
|
|
24440
24519
|
styleEl.textContent = rewriteCssAssetUrls(styleEl.textContent || "", compPath);
|
|
24441
24520
|
}
|
|
24442
24521
|
const rewrittenContent = contentDoc.body.innerHTML || content;
|
|
24443
|
-
const indexPath =
|
|
24522
|
+
const indexPath = join14(projectDir, "index.html");
|
|
24444
24523
|
let headContent = "";
|
|
24445
|
-
if (
|
|
24524
|
+
if (existsSync11(indexPath)) {
|
|
24446
24525
|
const indexHtml = readFileSync10(indexPath, "utf-8");
|
|
24447
24526
|
const headMatch = indexHtml.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
|
|
24448
24527
|
headContent = headMatch?.[1] ?? "";
|
|
@@ -24479,7 +24558,7 @@ var init_subComposition = __esm({
|
|
|
24479
24558
|
});
|
|
24480
24559
|
|
|
24481
24560
|
// ../core/src/studio-api/routes/preview.ts
|
|
24482
|
-
import { existsSync as
|
|
24561
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11, statSync as statSync2 } from "fs";
|
|
24483
24562
|
import { resolve as resolve10 } from "path";
|
|
24484
24563
|
function registerPreviewRoutes(api, adapter2) {
|
|
24485
24564
|
api.get("/projects/:id/preview", async (c2) => {
|
|
@@ -24489,7 +24568,7 @@ function registerPreviewRoutes(api, adapter2) {
|
|
|
24489
24568
|
let bundled = await adapter2.bundle(project.dir);
|
|
24490
24569
|
if (!bundled) {
|
|
24491
24570
|
const indexPath = resolve10(project.dir, "index.html");
|
|
24492
|
-
if (!
|
|
24571
|
+
if (!existsSync12(indexPath)) return c2.text("not found", 404);
|
|
24493
24572
|
bundled = readFileSync11(indexPath, "utf-8");
|
|
24494
24573
|
}
|
|
24495
24574
|
if (!bundled.includes("hyperframe.runtime") && !bundled.includes("hyperframes-preview-runtime")) {
|
|
@@ -24505,7 +24584,7 @@ ${runtimeTag}`;
|
|
|
24505
24584
|
return c2.html(bundled);
|
|
24506
24585
|
} catch {
|
|
24507
24586
|
const file = resolve10(project.dir, "index.html");
|
|
24508
|
-
if (
|
|
24587
|
+
if (existsSync12(file)) return c2.html(readFileSync11(file, "utf-8"));
|
|
24509
24588
|
return c2.text("not found", 404);
|
|
24510
24589
|
}
|
|
24511
24590
|
});
|
|
@@ -24516,7 +24595,7 @@ ${runtimeTag}`;
|
|
|
24516
24595
|
c2.req.path.replace(`/projects/${project.id}/preview/comp/`, "").split("?")[0] ?? ""
|
|
24517
24596
|
);
|
|
24518
24597
|
const compFile = resolve10(project.dir, compPath);
|
|
24519
|
-
if (!isSafePath(project.dir, compFile) || !
|
|
24598
|
+
if (!isSafePath(project.dir, compFile) || !existsSync12(compFile) || !statSync2(compFile).isFile()) {
|
|
24520
24599
|
return c2.text("not found", 404);
|
|
24521
24600
|
}
|
|
24522
24601
|
const baseHref = `/api/projects/${project.id}/preview/`;
|
|
@@ -24531,7 +24610,7 @@ ${runtimeTag}`;
|
|
|
24531
24610
|
c2.req.path.replace(`/projects/${project.id}/preview/`, "").split("?")[0] ?? ""
|
|
24532
24611
|
);
|
|
24533
24612
|
const file = resolve10(project.dir, subPath);
|
|
24534
|
-
if (!isSafePath(project.dir, file) || !
|
|
24613
|
+
if (!isSafePath(project.dir, file) || !existsSync12(file) || !statSync2(file).isFile()) {
|
|
24535
24614
|
return c2.text("not found", 404);
|
|
24536
24615
|
}
|
|
24537
24616
|
const contentType = getMimeType(subPath);
|
|
@@ -24570,14 +24649,14 @@ var init_preview = __esm({
|
|
|
24570
24649
|
"../core/src/studio-api/routes/preview.ts"() {
|
|
24571
24650
|
"use strict";
|
|
24572
24651
|
init_safePath();
|
|
24573
|
-
|
|
24652
|
+
init_mime();
|
|
24574
24653
|
init_subComposition();
|
|
24575
24654
|
}
|
|
24576
24655
|
});
|
|
24577
24656
|
|
|
24578
24657
|
// ../core/src/studio-api/routes/lint.ts
|
|
24579
24658
|
import { readFileSync as readFileSync12 } from "fs";
|
|
24580
|
-
import { join as
|
|
24659
|
+
import { join as join15 } from "path";
|
|
24581
24660
|
function registerLintRoutes(api, adapter2) {
|
|
24582
24661
|
api.get("/projects/:id/lint", async (c2) => {
|
|
24583
24662
|
const project = await adapter2.resolveProject(c2.req.param("id"));
|
|
@@ -24586,7 +24665,7 @@ function registerLintRoutes(api, adapter2) {
|
|
|
24586
24665
|
const htmlFiles = walkDir(project.dir).filter((f3) => f3.endsWith(".html"));
|
|
24587
24666
|
const allFindings = [];
|
|
24588
24667
|
for (const file of htmlFiles) {
|
|
24589
|
-
const content = readFileSync12(
|
|
24668
|
+
const content = readFileSync12(join15(project.dir, file), "utf-8");
|
|
24590
24669
|
const result = await adapter2.lint(content, { filePath: file });
|
|
24591
24670
|
if (result?.findings) {
|
|
24592
24671
|
for (const f3 of result.findings) {
|
|
@@ -24610,8 +24689,8 @@ var init_lint2 = __esm({
|
|
|
24610
24689
|
|
|
24611
24690
|
// ../core/src/studio-api/routes/render.ts
|
|
24612
24691
|
import { streamSSE } from "hono/streaming";
|
|
24613
|
-
import { existsSync as
|
|
24614
|
-
import { join as
|
|
24692
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13, mkdirSync as mkdirSync7, unlinkSync as unlinkSync4, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
24693
|
+
import { join as join16 } from "path";
|
|
24615
24694
|
function registerRenderRoutes(api, adapter2) {
|
|
24616
24695
|
const renderJobs = /* @__PURE__ */ new Map();
|
|
24617
24696
|
const TTL_MS = 3e5;
|
|
@@ -24648,9 +24727,9 @@ function registerRenderRoutes(api, adapter2) {
|
|
|
24648
24727
|
const timePart = now.toTimeString().slice(0, 8).replace(/:/g, "-");
|
|
24649
24728
|
const jobId = `${project.id}_${datePart}_${timePart}`;
|
|
24650
24729
|
const rendersDir = adapter2.rendersDir(project);
|
|
24651
|
-
if (!
|
|
24730
|
+
if (!existsSync13(rendersDir)) mkdirSync7(rendersDir, { recursive: true });
|
|
24652
24731
|
const ext = FORMAT_EXT2[format] ?? ".mp4";
|
|
24653
|
-
const outputPath =
|
|
24732
|
+
const outputPath = join16(rendersDir, `${jobId}${ext}`);
|
|
24654
24733
|
const jobState = adapter2.startRender({
|
|
24655
24734
|
project,
|
|
24656
24735
|
outputPath,
|
|
@@ -24715,7 +24794,7 @@ function registerRenderRoutes(api, adapter2) {
|
|
|
24715
24794
|
api.get("/render/:jobId/view", (c2) => {
|
|
24716
24795
|
const { jobId } = c2.req.param();
|
|
24717
24796
|
const job = renderJobs.get(jobId);
|
|
24718
|
-
if (!job?.outputPath || !
|
|
24797
|
+
if (!job?.outputPath || !existsSync13(job.outputPath)) {
|
|
24719
24798
|
return c2.json({ error: "not found" }, 404);
|
|
24720
24799
|
}
|
|
24721
24800
|
const contentType = renderContentType(job.outputPath);
|
|
@@ -24733,7 +24812,7 @@ function registerRenderRoutes(api, adapter2) {
|
|
|
24733
24812
|
api.get("/render/:jobId/download", (c2) => {
|
|
24734
24813
|
const { jobId } = c2.req.param();
|
|
24735
24814
|
const job = renderJobs.get(jobId);
|
|
24736
|
-
if (!job?.outputPath || !
|
|
24815
|
+
if (!job?.outputPath || !existsSync13(job.outputPath)) {
|
|
24737
24816
|
return c2.json({ error: "not found" }, 404);
|
|
24738
24817
|
}
|
|
24739
24818
|
const contentType = renderContentType(job.outputPath);
|
|
@@ -24752,8 +24831,8 @@ function registerRenderRoutes(api, adapter2) {
|
|
|
24752
24831
|
if (state.id === jobId && state.outputPath) {
|
|
24753
24832
|
const dir = state.outputPath.replace(/\/[^/]+$/, "");
|
|
24754
24833
|
for (const ext of [".mp4", ".webm", ".mov", ".meta.json"]) {
|
|
24755
|
-
const fp =
|
|
24756
|
-
if (
|
|
24834
|
+
const fp = join16(dir, `${jobId}${ext}`);
|
|
24835
|
+
if (existsSync13(fp)) unlinkSync4(fp);
|
|
24757
24836
|
}
|
|
24758
24837
|
break;
|
|
24759
24838
|
}
|
|
@@ -24767,8 +24846,8 @@ function registerRenderRoutes(api, adapter2) {
|
|
|
24767
24846
|
const filename = c2.req.path.split("/renders/file/")[1];
|
|
24768
24847
|
if (!filename) return c2.json({ error: "missing filename" }, 400);
|
|
24769
24848
|
const rendersDir = adapter2.rendersDir(project);
|
|
24770
|
-
const fp =
|
|
24771
|
-
if (!
|
|
24849
|
+
const fp = join16(rendersDir, filename);
|
|
24850
|
+
if (!existsSync13(fp)) return c2.json({ error: "not found" }, 404);
|
|
24772
24851
|
const contentType = renderContentType(fp);
|
|
24773
24852
|
const content = readFileSync13(fp);
|
|
24774
24853
|
return new Response(content, {
|
|
@@ -24784,15 +24863,15 @@ function registerRenderRoutes(api, adapter2) {
|
|
|
24784
24863
|
const project = await adapter2.resolveProject(c2.req.param("id"));
|
|
24785
24864
|
if (!project) return c2.json({ error: "not found" }, 404);
|
|
24786
24865
|
const rendersDir = adapter2.rendersDir(project);
|
|
24787
|
-
if (!
|
|
24866
|
+
if (!existsSync13(rendersDir)) return c2.json({ renders: [] });
|
|
24788
24867
|
const files = readdirSync5(rendersDir).filter((f3) => f3.endsWith(".mp4") || f3.endsWith(".webm") || f3.endsWith(".mov")).map((f3) => {
|
|
24789
|
-
const fp =
|
|
24868
|
+
const fp = join16(rendersDir, f3);
|
|
24790
24869
|
const stat3 = statSync3(fp);
|
|
24791
24870
|
const rid = f3.replace(/\.(mp4|webm|mov)$/, "");
|
|
24792
|
-
const metaPath =
|
|
24871
|
+
const metaPath = join16(rendersDir, `${rid}.meta.json`);
|
|
24793
24872
|
let status = "complete";
|
|
24794
24873
|
let durationMs;
|
|
24795
|
-
if (
|
|
24874
|
+
if (existsSync13(metaPath)) {
|
|
24796
24875
|
try {
|
|
24797
24876
|
const meta = JSON.parse(readFileSync13(metaPath, "utf-8"));
|
|
24798
24877
|
if (meta.status === "failed") status = "failed";
|
|
@@ -24815,7 +24894,7 @@ function registerRenderRoutes(api, adapter2) {
|
|
|
24815
24894
|
id: file.id,
|
|
24816
24895
|
status: file.status,
|
|
24817
24896
|
progress: 100,
|
|
24818
|
-
outputPath:
|
|
24897
|
+
outputPath: join16(rendersDir, file.filename),
|
|
24819
24898
|
createdAt: file.createdAt
|
|
24820
24899
|
});
|
|
24821
24900
|
}
|
|
@@ -24830,8 +24909,8 @@ var init_render = __esm({
|
|
|
24830
24909
|
});
|
|
24831
24910
|
|
|
24832
24911
|
// ../core/src/studio-api/routes/thumbnail.ts
|
|
24833
|
-
import { existsSync as
|
|
24834
|
-
import { join as
|
|
24912
|
+
import { existsSync as existsSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, statSync as statSync4 } from "fs";
|
|
24913
|
+
import { join as join17 } from "path";
|
|
24835
24914
|
function registerThumbnailRoutes(api, adapter2) {
|
|
24836
24915
|
api.get("/projects/:id/thumbnail/*", async (c2) => {
|
|
24837
24916
|
if (!adapter2.generateThumbnail) {
|
|
@@ -24853,8 +24932,8 @@ function registerThumbnailRoutes(api, adapter2) {
|
|
|
24853
24932
|
let compH = vpHeight || 1080;
|
|
24854
24933
|
let sourceMtime = 0;
|
|
24855
24934
|
if (!vpWidth) {
|
|
24856
|
-
const htmlFile =
|
|
24857
|
-
if (
|
|
24935
|
+
const htmlFile = join17(project.dir, compPath);
|
|
24936
|
+
if (existsSync14(htmlFile)) {
|
|
24858
24937
|
sourceMtime = Math.round(statSync4(htmlFile).mtimeMs);
|
|
24859
24938
|
const html = readFileSync14(htmlFile, "utf-8");
|
|
24860
24939
|
const wMatch = html.match(/data-width=["'](\d+)["']/);
|
|
@@ -24864,12 +24943,12 @@ function registerThumbnailRoutes(api, adapter2) {
|
|
|
24864
24943
|
}
|
|
24865
24944
|
}
|
|
24866
24945
|
const previewUrl = compPath === "index.html" ? `http://${c2.req.header("host")}/api/projects/${project.id}/preview` : `http://${c2.req.header("host")}/api/projects/${project.id}/preview/comp/${compPath}`;
|
|
24867
|
-
const cacheDir =
|
|
24946
|
+
const cacheDir = join17(project.dir, ".thumbnails");
|
|
24868
24947
|
const selectorKey = selector ? `_${selector.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 80)}` : "";
|
|
24869
24948
|
const urlVersionKey = urlVersion ? `_${urlVersion.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32)}` : "";
|
|
24870
24949
|
const cacheKey = `${THUMBNAIL_CACHE_VERSION}${urlVersionKey}_${compPath.replace(/\//g, "_")}_${compW}x${compH}_${sourceMtime}_${seekTime.toFixed(2)}${selectorKey}.jpg`;
|
|
24871
|
-
const cachePath2 =
|
|
24872
|
-
if (
|
|
24950
|
+
const cachePath2 = join17(cacheDir, cacheKey);
|
|
24951
|
+
if (existsSync14(cachePath2)) {
|
|
24873
24952
|
return new Response(new Uint8Array(readFileSync14(cachePath2)), {
|
|
24874
24953
|
headers: { "Content-Type": "image/jpeg", "Cache-Control": "public, max-age=60" }
|
|
24875
24954
|
});
|
|
@@ -24887,8 +24966,8 @@ function registerThumbnailRoutes(api, adapter2) {
|
|
|
24887
24966
|
if (!buffer) {
|
|
24888
24967
|
return c2.json({ error: "Thumbnail generation returned null" }, 500);
|
|
24889
24968
|
}
|
|
24890
|
-
if (!
|
|
24891
|
-
|
|
24969
|
+
if (!existsSync14(cacheDir)) mkdirSync8(cacheDir, { recursive: true });
|
|
24970
|
+
writeFileSync8(cachePath2, buffer);
|
|
24892
24971
|
return new Response(new Uint8Array(buffer), {
|
|
24893
24972
|
headers: { "Content-Type": "image/jpeg", "Cache-Control": "public, max-age=60" }
|
|
24894
24973
|
});
|
|
@@ -24906,11 +24985,55 @@ var init_thumbnail = __esm({
|
|
|
24906
24985
|
}
|
|
24907
24986
|
});
|
|
24908
24987
|
|
|
24988
|
+
// ../core/src/studio-api/routes/waveform.ts
|
|
24989
|
+
import { existsSync as existsSync15, readFileSync as readFileSync15, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "fs";
|
|
24990
|
+
import { join as join18 } from "path";
|
|
24991
|
+
function registerWaveformRoutes(api, adapter2) {
|
|
24992
|
+
api.get("/projects/:id/waveform/*", async (c2) => {
|
|
24993
|
+
const project = await adapter2.resolveProject(c2.req.param("id"));
|
|
24994
|
+
if (!project) return c2.json({ error: "not found" }, 404);
|
|
24995
|
+
const assetPath = decodeURIComponent(
|
|
24996
|
+
c2.req.path.replace(`/projects/${project.id}/waveform/`, "").split("?")[0] ?? ""
|
|
24997
|
+
);
|
|
24998
|
+
const audioPath = join18(project.dir, assetPath);
|
|
24999
|
+
if (!existsSync15(audioPath)) return c2.json({ error: "file not found" }, 404);
|
|
25000
|
+
const cacheDir = join18(project.dir, ".waveform-cache");
|
|
25001
|
+
const cachePath2 = join18(cacheDir, buildWaveformCacheKey(assetPath));
|
|
25002
|
+
if (existsSync15(cachePath2)) {
|
|
25003
|
+
try {
|
|
25004
|
+
const peaks2 = JSON.parse(readFileSync15(cachePath2, "utf-8"));
|
|
25005
|
+
return c2.json({ peaks: peaks2 });
|
|
25006
|
+
} catch {
|
|
25007
|
+
}
|
|
25008
|
+
}
|
|
25009
|
+
let peaks;
|
|
25010
|
+
try {
|
|
25011
|
+
peaks = await decodeAudioPeaks(audioPath);
|
|
25012
|
+
} catch {
|
|
25013
|
+
return c2.json({ error: "failed to decode audio" }, 500);
|
|
25014
|
+
}
|
|
25015
|
+
try {
|
|
25016
|
+
mkdirSync9(cacheDir, { recursive: true });
|
|
25017
|
+
writeFileSync9(cachePath2, JSON.stringify(peaks));
|
|
25018
|
+
} catch {
|
|
25019
|
+
}
|
|
25020
|
+
return c2.json({ peaks });
|
|
25021
|
+
});
|
|
25022
|
+
}
|
|
25023
|
+
var init_waveform2 = __esm({
|
|
25024
|
+
"../core/src/studio-api/routes/waveform.ts"() {
|
|
25025
|
+
"use strict";
|
|
25026
|
+
init_waveform();
|
|
25027
|
+
init_mime();
|
|
25028
|
+
init_waveform();
|
|
25029
|
+
}
|
|
25030
|
+
});
|
|
25031
|
+
|
|
24909
25032
|
// ../core/src/studio-api/routes/fonts.ts
|
|
24910
25033
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
24911
|
-
import { existsSync as
|
|
25034
|
+
import { existsSync as existsSync16, readdirSync as readdirSync6, statSync as statSync5 } from "fs";
|
|
24912
25035
|
import { homedir as homedir4, platform as platform3 } from "os";
|
|
24913
|
-
import { join as
|
|
25036
|
+
import { join as join19 } from "path";
|
|
24914
25037
|
function isRecord(value) {
|
|
24915
25038
|
return typeof value === "object" && value !== null;
|
|
24916
25039
|
}
|
|
@@ -24918,18 +25041,18 @@ function fontDirectories() {
|
|
|
24918
25041
|
const home = homedir4();
|
|
24919
25042
|
if (platform3() === "darwin") {
|
|
24920
25043
|
return [
|
|
24921
|
-
|
|
25044
|
+
join19(home, "Library", "Fonts"),
|
|
24922
25045
|
"/Library/Fonts",
|
|
24923
25046
|
"/System/Library/Fonts",
|
|
24924
25047
|
"/System/Library/Fonts/Supplemental"
|
|
24925
25048
|
];
|
|
24926
25049
|
}
|
|
24927
25050
|
if (platform3() === "win32") {
|
|
24928
|
-
return [
|
|
25051
|
+
return [join19(process.env.WINDIR || "C:\\Windows", "Fonts")];
|
|
24929
25052
|
}
|
|
24930
25053
|
return [
|
|
24931
|
-
|
|
24932
|
-
|
|
25054
|
+
join19(home, ".fonts"),
|
|
25055
|
+
join19(home, ".local", "share", "fonts"),
|
|
24933
25056
|
"/usr/local/share/fonts",
|
|
24934
25057
|
"/usr/share/fonts"
|
|
24935
25058
|
];
|
|
@@ -24981,10 +25104,10 @@ function collectMacSystemProfilerFonts() {
|
|
|
24981
25104
|
return fonts;
|
|
24982
25105
|
}
|
|
24983
25106
|
function collectFontsFromDir(dir, depth = 0) {
|
|
24984
|
-
if (!
|
|
25107
|
+
if (!existsSync16(dir) || depth > 2) return [];
|
|
24985
25108
|
const fonts = [];
|
|
24986
25109
|
for (const entry of readdirSync6(dir, { withFileTypes: true })) {
|
|
24987
|
-
const fullPath =
|
|
25110
|
+
const fullPath = join19(dir, entry.name);
|
|
24988
25111
|
if (entry.isDirectory()) {
|
|
24989
25112
|
fonts.push(...collectFontsFromDir(fullPath, depth + 1));
|
|
24990
25113
|
continue;
|
|
@@ -25128,6 +25251,7 @@ function createStudioApi(adapter2) {
|
|
|
25128
25251
|
registerLintRoutes(api, adapter2);
|
|
25129
25252
|
registerRenderRoutes(api, adapter2);
|
|
25130
25253
|
registerThumbnailRoutes(api, adapter2);
|
|
25254
|
+
registerWaveformRoutes(api, adapter2);
|
|
25131
25255
|
registerFontRoutes(api);
|
|
25132
25256
|
return api;
|
|
25133
25257
|
}
|
|
@@ -25140,6 +25264,7 @@ var init_createStudioApi = __esm({
|
|
|
25140
25264
|
init_lint2();
|
|
25141
25265
|
init_render();
|
|
25142
25266
|
init_thumbnail();
|
|
25267
|
+
init_waveform2();
|
|
25143
25268
|
init_fonts();
|
|
25144
25269
|
}
|
|
25145
25270
|
});
|
|
@@ -25159,7 +25284,7 @@ var init_studio_api = __esm({
|
|
|
25159
25284
|
"use strict";
|
|
25160
25285
|
init_createStudioApi();
|
|
25161
25286
|
init_safePath();
|
|
25162
|
-
|
|
25287
|
+
init_mime();
|
|
25163
25288
|
init_subComposition();
|
|
25164
25289
|
}
|
|
25165
25290
|
});
|
|
@@ -25175,9 +25300,9 @@ __export(manager_exports2, {
|
|
|
25175
25300
|
setBrowserPath: () => setBrowserPath
|
|
25176
25301
|
});
|
|
25177
25302
|
import { execSync } from "child_process";
|
|
25178
|
-
import { existsSync as
|
|
25303
|
+
import { existsSync as existsSync17, rmSync as rmSync4 } from "fs";
|
|
25179
25304
|
import { homedir as homedir5 } from "os";
|
|
25180
|
-
import { join as
|
|
25305
|
+
import { join as join20 } from "path";
|
|
25181
25306
|
import { Browser, detectBrowserPlatform, getInstalledBrowsers, install } from "@puppeteer/browsers";
|
|
25182
25307
|
function setBrowserPath(path2) {
|
|
25183
25308
|
_browserPathOverride = path2;
|
|
@@ -25197,17 +25322,17 @@ function whichBinary2(name) {
|
|
|
25197
25322
|
}
|
|
25198
25323
|
}
|
|
25199
25324
|
function findFromEnv2() {
|
|
25200
|
-
if (_browserPathOverride &&
|
|
25325
|
+
if (_browserPathOverride && existsSync17(_browserPathOverride)) {
|
|
25201
25326
|
return { executablePath: _browserPathOverride, source: "env" };
|
|
25202
25327
|
}
|
|
25203
25328
|
const envPath = process.env["HYPERFRAMES_BROWSER_PATH"];
|
|
25204
|
-
if (envPath &&
|
|
25329
|
+
if (envPath && existsSync17(envPath)) {
|
|
25205
25330
|
return { executablePath: envPath, source: "env" };
|
|
25206
25331
|
}
|
|
25207
25332
|
return void 0;
|
|
25208
25333
|
}
|
|
25209
25334
|
async function findFromCache() {
|
|
25210
|
-
if (!
|
|
25335
|
+
if (!existsSync17(CACHE_DIR2)) {
|
|
25211
25336
|
return void 0;
|
|
25212
25337
|
}
|
|
25213
25338
|
const installed = await getInstalledBrowsers({ cacheDir: CACHE_DIR2 });
|
|
@@ -25219,7 +25344,7 @@ async function findFromCache() {
|
|
|
25219
25344
|
}
|
|
25220
25345
|
function findFromSystem2() {
|
|
25221
25346
|
for (const p of SYSTEM_CHROME_PATHS) {
|
|
25222
|
-
if (
|
|
25347
|
+
if (existsSync17(p)) {
|
|
25223
25348
|
return { executablePath: p, source: "system" };
|
|
25224
25349
|
}
|
|
25225
25350
|
}
|
|
@@ -25253,7 +25378,7 @@ async function ensureBrowser(options) {
|
|
|
25253
25378
|
return { executablePath: installed.executablePath, source: "download" };
|
|
25254
25379
|
}
|
|
25255
25380
|
function clearBrowser() {
|
|
25256
|
-
if (!
|
|
25381
|
+
if (!existsSync17(CACHE_DIR2)) {
|
|
25257
25382
|
return false;
|
|
25258
25383
|
}
|
|
25259
25384
|
rmSync4(CACHE_DIR2, { recursive: true, force: true });
|
|
@@ -25264,7 +25389,7 @@ var init_manager2 = __esm({
|
|
|
25264
25389
|
"src/browser/manager.ts"() {
|
|
25265
25390
|
"use strict";
|
|
25266
25391
|
CHROME_VERSION = "131.0.6778.85";
|
|
25267
|
-
CACHE_DIR2 =
|
|
25392
|
+
CACHE_DIR2 = join20(homedir5(), ".cache", "hyperframes", "chrome");
|
|
25268
25393
|
SYSTEM_CHROME_PATHS = process.platform === "darwin" ? ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"] : [
|
|
25269
25394
|
"/usr/bin/google-chrome",
|
|
25270
25395
|
"/usr/bin/google-chrome-stable",
|
|
@@ -25391,8 +25516,8 @@ var init_config2 = __esm({
|
|
|
25391
25516
|
});
|
|
25392
25517
|
|
|
25393
25518
|
// ../engine/src/services/browserManager.ts
|
|
25394
|
-
import { existsSync as
|
|
25395
|
-
import { join as
|
|
25519
|
+
import { existsSync as existsSync18, readdirSync as readdirSync7 } from "fs";
|
|
25520
|
+
import { join as join21 } from "path";
|
|
25396
25521
|
import { homedir as homedir6 } from "os";
|
|
25397
25522
|
async function getPuppeteer() {
|
|
25398
25523
|
if (_puppeteer) return _puppeteer;
|
|
@@ -25413,19 +25538,19 @@ function resolveHeadlessShellPath(config) {
|
|
|
25413
25538
|
if (process.env.PRODUCER_HEADLESS_SHELL_PATH) {
|
|
25414
25539
|
return process.env.PRODUCER_HEADLESS_SHELL_PATH;
|
|
25415
25540
|
}
|
|
25416
|
-
const baseDir =
|
|
25417
|
-
if (!
|
|
25541
|
+
const baseDir = join21(homedir6(), ".cache", "puppeteer", "chrome-headless-shell");
|
|
25542
|
+
if (!existsSync18(baseDir)) return void 0;
|
|
25418
25543
|
try {
|
|
25419
25544
|
const versions = readdirSync7(baseDir).sort().reverse();
|
|
25420
25545
|
for (const version of versions) {
|
|
25421
25546
|
const candidates = [
|
|
25422
|
-
|
|
25423
|
-
|
|
25424
|
-
|
|
25425
|
-
|
|
25547
|
+
join21(baseDir, version, "chrome-headless-shell-linux64", "chrome-headless-shell"),
|
|
25548
|
+
join21(baseDir, version, "chrome-headless-shell-mac-arm64", "chrome-headless-shell"),
|
|
25549
|
+
join21(baseDir, version, "chrome-headless-shell-mac-x64", "chrome-headless-shell"),
|
|
25550
|
+
join21(baseDir, version, "chrome-headless-shell-win64", "chrome-headless-shell.exe")
|
|
25426
25551
|
];
|
|
25427
25552
|
for (const binary of candidates) {
|
|
25428
|
-
if (
|
|
25553
|
+
if (existsSync18(binary)) return binary;
|
|
25429
25554
|
}
|
|
25430
25555
|
}
|
|
25431
25556
|
} catch {
|
|
@@ -25888,10 +26013,10 @@ var init_screenshotService = __esm({
|
|
|
25888
26013
|
});
|
|
25889
26014
|
|
|
25890
26015
|
// ../engine/src/services/frameCapture.ts
|
|
25891
|
-
import { existsSync as
|
|
25892
|
-
import { join as
|
|
26016
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
26017
|
+
import { join as join22 } from "path";
|
|
25893
26018
|
async function createCaptureSession(serverUrl, outputDir, options, onBeforeCapture = null, config) {
|
|
25894
|
-
if (!
|
|
26019
|
+
if (!existsSync19(outputDir)) mkdirSync10(outputDir, { recursive: true });
|
|
25895
26020
|
const headlessShell = resolveHeadlessShellPath(config);
|
|
25896
26021
|
const isLinux = process.platform === "linux";
|
|
25897
26022
|
const forceScreenshot = config?.forceScreenshot ?? DEFAULT_CONFIG2.forceScreenshot;
|
|
@@ -26095,13 +26220,13 @@ async function initializeSession(session) {
|
|
|
26095
26220
|
}
|
|
26096
26221
|
async function captureFrameErrorDiagnostics(session, frameIndex, time, error) {
|
|
26097
26222
|
try {
|
|
26098
|
-
const diagnosticsDir =
|
|
26099
|
-
if (!
|
|
26100
|
-
const base =
|
|
26223
|
+
const diagnosticsDir = join22(session.outputDir, "diagnostics");
|
|
26224
|
+
if (!existsSync19(diagnosticsDir)) mkdirSync10(diagnosticsDir, { recursive: true });
|
|
26225
|
+
const base = join22(diagnosticsDir, `frame-error-${frameIndex}`);
|
|
26101
26226
|
await session.page.screenshot({ path: `${base}.png`, type: "png", fullPage: true });
|
|
26102
26227
|
const html = await session.page.content();
|
|
26103
|
-
|
|
26104
|
-
|
|
26228
|
+
writeFileSync10(`${base}.html`, html, "utf-8");
|
|
26229
|
+
writeFileSync10(
|
|
26105
26230
|
`${base}.json`,
|
|
26106
26231
|
JSON.stringify(
|
|
26107
26232
|
{
|
|
@@ -26195,8 +26320,8 @@ async function captureFrame(session, frameIndex, time) {
|
|
|
26195
26320
|
);
|
|
26196
26321
|
const ext = options.format === "png" ? "png" : "jpg";
|
|
26197
26322
|
const frameName = `frame_${String(frameIndex).padStart(6, "0")}.${ext}`;
|
|
26198
|
-
const framePath =
|
|
26199
|
-
|
|
26323
|
+
const framePath = join22(outputDir, frameName);
|
|
26324
|
+
writeFileSync10(framePath, buffer);
|
|
26200
26325
|
return { frameIndex, time: quantizedTime, path: framePath, captureTimeMs };
|
|
26201
26326
|
}
|
|
26202
26327
|
async function captureFrameToBuffer(session, frameIndex, time) {
|
|
@@ -26216,8 +26341,8 @@ async function closeCaptureSession(session) {
|
|
|
26216
26341
|
session.isInitialized = false;
|
|
26217
26342
|
}
|
|
26218
26343
|
function prepareCaptureSessionForReuse(session, outputDir, onBeforeCapture) {
|
|
26219
|
-
if (!
|
|
26220
|
-
|
|
26344
|
+
if (!existsSync19(outputDir)) {
|
|
26345
|
+
mkdirSync10(outputDir, { recursive: true });
|
|
26221
26346
|
}
|
|
26222
26347
|
session.outputDir = outputDir;
|
|
26223
26348
|
session.onBeforeCapture = onBeforeCapture;
|
|
@@ -26260,10 +26385,10 @@ var init_frameCapture = __esm({
|
|
|
26260
26385
|
});
|
|
26261
26386
|
|
|
26262
26387
|
// ../engine/src/utils/gpuEncoder.ts
|
|
26263
|
-
import { spawn as
|
|
26388
|
+
import { spawn as spawn3 } from "child_process";
|
|
26264
26389
|
async function detectGpuEncoder() {
|
|
26265
26390
|
return new Promise((resolve39) => {
|
|
26266
|
-
const ffmpeg =
|
|
26391
|
+
const ffmpeg = spawn3("ffmpeg", ["-encoders"], {
|
|
26267
26392
|
stdio: ["pipe", "pipe", "pipe"]
|
|
26268
26393
|
});
|
|
26269
26394
|
let stdout2 = "";
|
|
@@ -26383,7 +26508,7 @@ var init_hdr = __esm({
|
|
|
26383
26508
|
});
|
|
26384
26509
|
|
|
26385
26510
|
// ../engine/src/utils/runFfmpeg.ts
|
|
26386
|
-
import { spawn as
|
|
26511
|
+
import { spawn as spawn4 } from "child_process";
|
|
26387
26512
|
function formatFfmpegError(exitCode, stderr, tailLines = DEFAULT_STDERR_TAIL_LINES) {
|
|
26388
26513
|
const tail = (stderr ?? "").split(/\r?\n/).filter((line) => line.length > 0).slice(-tailLines).join("\n");
|
|
26389
26514
|
if (exitCode === null) {
|
|
@@ -26399,7 +26524,7 @@ async function runFfmpeg(args, opts) {
|
|
|
26399
26524
|
const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;
|
|
26400
26525
|
const onStderr = opts?.onStderr;
|
|
26401
26526
|
return new Promise((resolve39) => {
|
|
26402
|
-
const ffmpeg =
|
|
26527
|
+
const ffmpeg = spawn4("ffmpeg", args);
|
|
26403
26528
|
let stderr = "";
|
|
26404
26529
|
const onAbort = () => {
|
|
26405
26530
|
ffmpeg.kill("SIGTERM");
|
|
@@ -26453,9 +26578,9 @@ var init_runFfmpeg = __esm({
|
|
|
26453
26578
|
});
|
|
26454
26579
|
|
|
26455
26580
|
// ../engine/src/services/chunkEncoder.ts
|
|
26456
|
-
import { spawn as
|
|
26457
|
-
import { copyFileSync, existsSync as
|
|
26458
|
-
import { join as
|
|
26581
|
+
import { spawn as spawn5 } from "child_process";
|
|
26582
|
+
import { copyFileSync, existsSync as existsSync20, mkdirSync as mkdirSync11, readdirSync as readdirSync8, statSync as statSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
26583
|
+
import { join as join23, dirname as dirname6 } from "path";
|
|
26459
26584
|
function getEncoderPreset(quality, format = "mp4", hdr) {
|
|
26460
26585
|
const base = ENCODER_PRESETS[quality];
|
|
26461
26586
|
if (format === "webm") {
|
|
@@ -26606,7 +26731,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
|
|
|
26606
26731
|
async function encodeFramesFromDir(framesDir, framePattern, outputPath, options, signal, config) {
|
|
26607
26732
|
const startTime = Date.now();
|
|
26608
26733
|
const outputDir = dirname6(outputPath);
|
|
26609
|
-
if (!
|
|
26734
|
+
if (!existsSync20(outputDir)) mkdirSync11(outputDir, { recursive: true });
|
|
26610
26735
|
const files = readdirSync8(framesDir).filter((f3) => f3.match(/\.(jpg|jpeg|png)$/i));
|
|
26611
26736
|
const frameCount = files.length;
|
|
26612
26737
|
if (frameCount === 0) {
|
|
@@ -26623,11 +26748,11 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
|
|
|
26623
26748
|
if (options.useGpu) {
|
|
26624
26749
|
gpuEncoder = await getCachedGpuEncoder();
|
|
26625
26750
|
}
|
|
26626
|
-
const inputPath =
|
|
26751
|
+
const inputPath = join23(framesDir, framePattern);
|
|
26627
26752
|
const inputArgs = ["-framerate", String(options.fps), "-i", inputPath];
|
|
26628
26753
|
const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
|
|
26629
26754
|
return new Promise((resolve39) => {
|
|
26630
|
-
const ffmpeg =
|
|
26755
|
+
const ffmpeg = spawn5("ffmpeg", args);
|
|
26631
26756
|
let stderr = "";
|
|
26632
26757
|
const onAbort = () => {
|
|
26633
26758
|
ffmpeg.kill("SIGTERM");
|
|
@@ -26672,7 +26797,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
|
|
|
26672
26797
|
});
|
|
26673
26798
|
return;
|
|
26674
26799
|
}
|
|
26675
|
-
const fileSize =
|
|
26800
|
+
const fileSize = existsSync20(outputPath) ? statSync6(outputPath).size : 0;
|
|
26676
26801
|
resolve39({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
|
|
26677
26802
|
});
|
|
26678
26803
|
ffmpeg.on("error", (err) => {
|
|
@@ -26704,8 +26829,8 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
26704
26829
|
}
|
|
26705
26830
|
const chunkSize = Math.max(30, Math.floor(chunkSizeFrames));
|
|
26706
26831
|
const chunkCount = Math.ceil(files.length / chunkSize);
|
|
26707
|
-
const chunkDir =
|
|
26708
|
-
if (!
|
|
26832
|
+
const chunkDir = join23(dirname6(outputPath), "chunk-encode");
|
|
26833
|
+
if (!existsSync20(chunkDir)) mkdirSync11(chunkDir, { recursive: true });
|
|
26709
26834
|
const chunkPaths = [];
|
|
26710
26835
|
for (let i2 = 0; i2 < chunkCount; i2++) {
|
|
26711
26836
|
if (signal?.aborted) {
|
|
@@ -26721,8 +26846,8 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
26721
26846
|
const startNumber = i2 * chunkSize;
|
|
26722
26847
|
const framesInChunk = Math.min(chunkSize, files.length - startNumber);
|
|
26723
26848
|
const ext = outputPath.endsWith(".webm") ? ".webm" : outputPath.endsWith(".mov") ? ".mov" : ".mp4";
|
|
26724
|
-
const chunkPath =
|
|
26725
|
-
const inputPath =
|
|
26849
|
+
const chunkPath = join23(chunkDir, `chunk_${String(i2).padStart(4, "0")}${ext}`);
|
|
26850
|
+
const inputPath = join23(framesDir, framePattern);
|
|
26726
26851
|
const inputArgs = [
|
|
26727
26852
|
"-framerate",
|
|
26728
26853
|
String(options.fps),
|
|
@@ -26737,7 +26862,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
26737
26862
|
if (options.useGpu) gpuEncoder = await getCachedGpuEncoder();
|
|
26738
26863
|
const args = buildEncoderArgs(options, inputArgs, chunkPath, gpuEncoder);
|
|
26739
26864
|
const chunkResult = await new Promise((resolve39) => {
|
|
26740
|
-
const ffmpeg =
|
|
26865
|
+
const ffmpeg = spawn5("ffmpeg", args);
|
|
26741
26866
|
let stderr = "";
|
|
26742
26867
|
ffmpeg.stderr.on("data", (d) => {
|
|
26743
26868
|
stderr += d.toString();
|
|
@@ -26762,9 +26887,9 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
26762
26887
|
}
|
|
26763
26888
|
chunkPaths.push(chunkPath);
|
|
26764
26889
|
}
|
|
26765
|
-
const concatListPath =
|
|
26890
|
+
const concatListPath = join23(chunkDir, "concat-list.txt");
|
|
26766
26891
|
const concatInput = chunkPaths.map((path2) => `file '${path2.replace(/'/g, "'\\''")}'`).join("\n");
|
|
26767
|
-
|
|
26892
|
+
writeFileSync11(concatListPath, concatInput, "utf-8");
|
|
26768
26893
|
const concatArgs = [
|
|
26769
26894
|
"-f",
|
|
26770
26895
|
"concat",
|
|
@@ -26778,7 +26903,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
26778
26903
|
outputPath
|
|
26779
26904
|
];
|
|
26780
26905
|
const concatResult = await new Promise((resolve39) => {
|
|
26781
|
-
const ffmpeg =
|
|
26906
|
+
const ffmpeg = spawn5("ffmpeg", concatArgs);
|
|
26782
26907
|
let stderr = "";
|
|
26783
26908
|
ffmpeg.stderr.on("data", (d) => {
|
|
26784
26909
|
stderr += d.toString();
|
|
@@ -26801,7 +26926,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
26801
26926
|
error: concatResult.error
|
|
26802
26927
|
};
|
|
26803
26928
|
}
|
|
26804
|
-
const fileSize =
|
|
26929
|
+
const fileSize = existsSync20(outputPath) ? statSync6(outputPath).size : 0;
|
|
26805
26930
|
return {
|
|
26806
26931
|
success: true,
|
|
26807
26932
|
outputPath,
|
|
@@ -26812,7 +26937,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
|
|
|
26812
26937
|
}
|
|
26813
26938
|
async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, config) {
|
|
26814
26939
|
const outputDir = dirname6(outputPath);
|
|
26815
|
-
if (!
|
|
26940
|
+
if (!existsSync20(outputDir)) mkdirSync11(outputDir, { recursive: true });
|
|
26816
26941
|
const isWebm = outputPath.endsWith(".webm");
|
|
26817
26942
|
const isMov = outputPath.endsWith(".mov");
|
|
26818
26943
|
const args = ["-i", videoPath, "-i", audioPath, "-c:v", "copy"];
|
|
@@ -26882,8 +27007,8 @@ var init_chunkEncoder = __esm({
|
|
|
26882
27007
|
});
|
|
26883
27008
|
|
|
26884
27009
|
// ../engine/src/services/streamingEncoder.ts
|
|
26885
|
-
import { spawn as
|
|
26886
|
-
import { existsSync as
|
|
27010
|
+
import { spawn as spawn6 } from "child_process";
|
|
27011
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync12, statSync as statSync7 } from "fs";
|
|
26887
27012
|
import { dirname as dirname7 } from "path";
|
|
26888
27013
|
function createFrameReorderBuffer(startFrame, endFrame) {
|
|
26889
27014
|
let cursor = startFrame;
|
|
@@ -27066,14 +27191,14 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
|
|
|
27066
27191
|
}
|
|
27067
27192
|
async function spawnStreamingEncoder(outputPath, options, signal, config) {
|
|
27068
27193
|
const outputDir = dirname7(outputPath);
|
|
27069
|
-
if (!
|
|
27194
|
+
if (!existsSync21(outputDir)) mkdirSync12(outputDir, { recursive: true });
|
|
27070
27195
|
let gpuEncoder = null;
|
|
27071
27196
|
if (options.useGpu) {
|
|
27072
27197
|
gpuEncoder = await getCachedGpuEncoder();
|
|
27073
27198
|
}
|
|
27074
27199
|
const args = buildStreamingArgs(options, outputPath, gpuEncoder);
|
|
27075
27200
|
const startTime = Date.now();
|
|
27076
|
-
const ffmpeg =
|
|
27201
|
+
const ffmpeg = spawn6("ffmpeg", args, {
|
|
27077
27202
|
stdio: ["pipe", "pipe", "pipe"]
|
|
27078
27203
|
});
|
|
27079
27204
|
let exitStatus = "running";
|
|
@@ -27148,7 +27273,7 @@ Process error: ${err.message}`;
|
|
|
27148
27273
|
error: formatFfmpegError(exitCode, stderr)
|
|
27149
27274
|
};
|
|
27150
27275
|
}
|
|
27151
|
-
const fileSize =
|
|
27276
|
+
const fileSize = existsSync21(outputPath) ? statSync7(outputPath).size : 0;
|
|
27152
27277
|
return { success: true, durationMs, fileSize };
|
|
27153
27278
|
},
|
|
27154
27279
|
getExitStatus: () => exitStatus
|
|
@@ -27166,12 +27291,12 @@ var init_streamingEncoder = __esm({
|
|
|
27166
27291
|
});
|
|
27167
27292
|
|
|
27168
27293
|
// ../engine/src/utils/ffprobe.ts
|
|
27169
|
-
import { spawn as
|
|
27170
|
-
import { readFileSync as
|
|
27294
|
+
import { spawn as spawn7 } from "child_process";
|
|
27295
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
27171
27296
|
import { extname as extname4 } from "path";
|
|
27172
27297
|
function runFfprobe(args) {
|
|
27173
27298
|
return new Promise((resolve39, reject) => {
|
|
27174
|
-
const proc =
|
|
27299
|
+
const proc = spawn7("ffprobe", args);
|
|
27175
27300
|
let stdout2 = "";
|
|
27176
27301
|
let stderr = "";
|
|
27177
27302
|
proc.stdout.on("data", (data) => {
|
|
@@ -27261,7 +27386,7 @@ function extractPngMetadataFromBuffer(buf) {
|
|
|
27261
27386
|
function extractStillImageMetadata(filePath) {
|
|
27262
27387
|
if (extname4(filePath).toLowerCase() !== ".png") return null;
|
|
27263
27388
|
try {
|
|
27264
|
-
return extractPngMetadataFromBuffer(
|
|
27389
|
+
return extractPngMetadataFromBuffer(readFileSync16(filePath));
|
|
27265
27390
|
} catch {
|
|
27266
27391
|
return null;
|
|
27267
27392
|
}
|
|
@@ -27440,9 +27565,9 @@ var init_ffprobe = __esm({
|
|
|
27440
27565
|
});
|
|
27441
27566
|
|
|
27442
27567
|
// ../engine/src/utils/urlDownloader.ts
|
|
27443
|
-
import { createWriteStream as createWriteStream2, existsSync as
|
|
27568
|
+
import { createWriteStream as createWriteStream2, existsSync as existsSync22, mkdirSync as mkdirSync13 } from "fs";
|
|
27444
27569
|
import { createHash } from "crypto";
|
|
27445
|
-
import { join as
|
|
27570
|
+
import { join as join24, extname as extname5 } from "path";
|
|
27446
27571
|
import { Readable } from "stream";
|
|
27447
27572
|
import { finished } from "stream/promises";
|
|
27448
27573
|
function getFilenameFromUrl(url) {
|
|
@@ -27453,19 +27578,19 @@ function getFilenameFromUrl(url) {
|
|
|
27453
27578
|
}
|
|
27454
27579
|
async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
|
|
27455
27580
|
const cachedPath = downloadPathCache.get(url);
|
|
27456
|
-
if (cachedPath &&
|
|
27581
|
+
if (cachedPath && existsSync22(cachedPath)) {
|
|
27457
27582
|
return cachedPath;
|
|
27458
27583
|
}
|
|
27459
27584
|
const inFlight = inFlightDownloads.get(url);
|
|
27460
27585
|
if (inFlight) {
|
|
27461
27586
|
return inFlight;
|
|
27462
27587
|
}
|
|
27463
|
-
if (!
|
|
27464
|
-
|
|
27588
|
+
if (!existsSync22(destDir)) {
|
|
27589
|
+
mkdirSync13(destDir, { recursive: true });
|
|
27465
27590
|
}
|
|
27466
27591
|
const filename = getFilenameFromUrl(url);
|
|
27467
|
-
const localPath =
|
|
27468
|
-
if (
|
|
27592
|
+
const localPath = join24(destDir, filename);
|
|
27593
|
+
if (existsSync22(localPath)) {
|
|
27469
27594
|
downloadPathCache.set(url, localPath);
|
|
27470
27595
|
return localPath;
|
|
27471
27596
|
}
|
|
@@ -27557,9 +27682,9 @@ var init_htmlTemplate = __esm({
|
|
|
27557
27682
|
|
|
27558
27683
|
// ../engine/src/services/extractionCache.ts
|
|
27559
27684
|
import { createHash as createHash2 } from "crypto";
|
|
27560
|
-
import { mkdirSync as
|
|
27561
|
-
import { existsSync as
|
|
27562
|
-
import { join as
|
|
27685
|
+
import { mkdirSync as mkdirSync14, readdirSync as readdirSync9, statSync as statSync8, writeFileSync as writeFileSync12 } from "fs";
|
|
27686
|
+
import { existsSync as existsSync23 } from "fs";
|
|
27687
|
+
import { join as join25 } from "path";
|
|
27563
27688
|
function readKeyStat(videoPath) {
|
|
27564
27689
|
try {
|
|
27565
27690
|
const stat3 = statSync8(videoPath);
|
|
@@ -27588,15 +27713,15 @@ function cacheEntryDirName(keyHash) {
|
|
|
27588
27713
|
}
|
|
27589
27714
|
function lookupCacheEntry(rootDir, input) {
|
|
27590
27715
|
const keyHash = computeCacheKey(input);
|
|
27591
|
-
const dir =
|
|
27592
|
-
const complete =
|
|
27716
|
+
const dir = join25(rootDir, cacheEntryDirName(keyHash));
|
|
27717
|
+
const complete = existsSync23(join25(dir, COMPLETE_SENTINEL));
|
|
27593
27718
|
return { entry: { dir, keyHash }, hit: complete };
|
|
27594
27719
|
}
|
|
27595
27720
|
function ensureCacheEntryDir(entry) {
|
|
27596
|
-
|
|
27721
|
+
mkdirSync14(entry.dir, { recursive: true });
|
|
27597
27722
|
}
|
|
27598
27723
|
function markCacheEntryComplete(entry) {
|
|
27599
|
-
|
|
27724
|
+
writeFileSync12(join25(entry.dir, COMPLETE_SENTINEL), "", "utf-8");
|
|
27600
27725
|
}
|
|
27601
27726
|
function rehydrateCacheEntry(entry, options) {
|
|
27602
27727
|
const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${options.format}`;
|
|
@@ -27604,7 +27729,7 @@ function rehydrateCacheEntry(entry, options) {
|
|
|
27604
27729
|
const suffix = `.${options.format}`;
|
|
27605
27730
|
const files = readdirSync9(entry.dir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(suffix)).sort();
|
|
27606
27731
|
files.forEach((file, idx) => {
|
|
27607
|
-
framePaths.set(idx,
|
|
27732
|
+
framePaths.set(idx, join25(entry.dir, file));
|
|
27608
27733
|
});
|
|
27609
27734
|
return {
|
|
27610
27735
|
videoId: options.videoId,
|
|
@@ -27629,9 +27754,9 @@ var init_extractionCache = __esm({
|
|
|
27629
27754
|
});
|
|
27630
27755
|
|
|
27631
27756
|
// ../engine/src/services/videoFrameExtractor.ts
|
|
27632
|
-
import { spawn as
|
|
27633
|
-
import { existsSync as
|
|
27634
|
-
import { isAbsolute as isAbsolute2, join as
|
|
27757
|
+
import { spawn as spawn8 } from "child_process";
|
|
27758
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync15, readdirSync as readdirSync10, rmSync as rmSync5 } from "fs";
|
|
27759
|
+
import { isAbsolute as isAbsolute2, join as join26 } from "path";
|
|
27635
27760
|
function parseVideoElements(html) {
|
|
27636
27761
|
const videos = [];
|
|
27637
27762
|
const { document: document2 } = parseHTML(unwrapTemplate(html));
|
|
@@ -27701,12 +27826,12 @@ function parseImageElements(html) {
|
|
|
27701
27826
|
async function extractVideoFramesRange(videoPath, videoId, startTime, duration, options, signal, config, outputDirOverride) {
|
|
27702
27827
|
const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
|
|
27703
27828
|
const { fps, outputDir, quality = 95 } = options;
|
|
27704
|
-
const videoOutputDir = outputDirOverride ??
|
|
27705
|
-
if (!
|
|
27829
|
+
const videoOutputDir = outputDirOverride ?? join26(outputDir, videoId);
|
|
27830
|
+
if (!existsSync24(videoOutputDir)) mkdirSync15(videoOutputDir, { recursive: true });
|
|
27706
27831
|
const metadata = await extractMediaMetadata(videoPath);
|
|
27707
27832
|
const format = resolveFrameFormat(metadata, options.format);
|
|
27708
27833
|
const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${format}`;
|
|
27709
|
-
const outputPattern =
|
|
27834
|
+
const outputPattern = join26(videoOutputDir, framePattern);
|
|
27710
27835
|
const isHdr = isHdrColorSpace(metadata.colorSpace);
|
|
27711
27836
|
const isMacOS = process.platform === "darwin";
|
|
27712
27837
|
const args = [];
|
|
@@ -27727,7 +27852,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
|
|
|
27727
27852
|
if (format === "png") args.push("-compression_level", "6");
|
|
27728
27853
|
args.push("-y", outputPattern);
|
|
27729
27854
|
return new Promise((resolve39, reject) => {
|
|
27730
|
-
const ffmpeg =
|
|
27855
|
+
const ffmpeg = spawn8("ffmpeg", args);
|
|
27731
27856
|
let stderr = "";
|
|
27732
27857
|
const onAbort = () => {
|
|
27733
27858
|
ffmpeg.kill("SIGTERM");
|
|
@@ -27759,7 +27884,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
|
|
|
27759
27884
|
const framePaths = /* @__PURE__ */ new Map();
|
|
27760
27885
|
const files = readdirSync10(videoOutputDir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(`.${format}`)).sort();
|
|
27761
27886
|
files.forEach((file, index) => {
|
|
27762
|
-
framePaths.set(index,
|
|
27887
|
+
framePaths.set(index, join26(videoOutputDir, file));
|
|
27763
27888
|
});
|
|
27764
27889
|
resolve39({
|
|
27765
27890
|
videoId,
|
|
@@ -27886,15 +28011,15 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
|
|
|
27886
28011
|
try {
|
|
27887
28012
|
let videoPath = video.src;
|
|
27888
28013
|
if (!isAbsolute2(videoPath) && !isHttpUrl(videoPath)) {
|
|
27889
|
-
const fromCompiled = compiledDir ?
|
|
27890
|
-
videoPath = fromCompiled &&
|
|
28014
|
+
const fromCompiled = compiledDir ? join26(compiledDir, videoPath) : null;
|
|
28015
|
+
videoPath = fromCompiled && existsSync24(fromCompiled) ? fromCompiled : join26(baseDir, videoPath);
|
|
27891
28016
|
}
|
|
27892
28017
|
if (isHttpUrl(videoPath)) {
|
|
27893
|
-
const downloadDir =
|
|
27894
|
-
|
|
28018
|
+
const downloadDir = join26(options.outputDir, "_downloads");
|
|
28019
|
+
mkdirSync15(downloadDir, { recursive: true });
|
|
27895
28020
|
videoPath = await downloadToTemp(videoPath, downloadDir);
|
|
27896
28021
|
}
|
|
27897
|
-
if (!
|
|
28022
|
+
if (!existsSync24(videoPath)) {
|
|
27898
28023
|
errors.push({ videoId: video.id, error: `Video file not found: ${videoPath}` });
|
|
27899
28024
|
continue;
|
|
27900
28025
|
}
|
|
@@ -27927,8 +28052,8 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
|
|
|
27927
28052
|
const hdrSkippedIndices = /* @__PURE__ */ new Set();
|
|
27928
28053
|
if (hdrInfo.hasHdr && hdrInfo.dominantTransfer) {
|
|
27929
28054
|
const targetTransfer = hdrInfo.dominantTransfer;
|
|
27930
|
-
const convertDir =
|
|
27931
|
-
|
|
28055
|
+
const convertDir = join26(options.outputDir, "_hdr_normalized");
|
|
28056
|
+
mkdirSync15(convertDir, { recursive: true });
|
|
27932
28057
|
for (let i2 = 0; i2 < resolvedVideos.length; i2++) {
|
|
27933
28058
|
if (signal?.aborted) break;
|
|
27934
28059
|
const cs = videoColorSpaces[i2] ?? null;
|
|
@@ -27949,7 +28074,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
|
|
|
27949
28074
|
const sourceRemaining = metadata.durationSeconds - entry.video.mediaStart;
|
|
27950
28075
|
segDuration = sourceRemaining > 0 ? sourceRemaining : metadata.durationSeconds;
|
|
27951
28076
|
}
|
|
27952
|
-
const convertedPath =
|
|
28077
|
+
const convertedPath = join26(convertDir, `${entry.video.id}_hdr.mp4`);
|
|
27953
28078
|
try {
|
|
27954
28079
|
await convertSdrToHdr(
|
|
27955
28080
|
entry.videoPath,
|
|
@@ -27984,7 +28109,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
|
|
|
27984
28109
|
}
|
|
27985
28110
|
}
|
|
27986
28111
|
const vfrPreflightStart = Date.now();
|
|
27987
|
-
const vfrNormDir =
|
|
28112
|
+
const vfrNormDir = join26(options.outputDir, "_vfr_normalized");
|
|
27988
28113
|
for (let i2 = 0; i2 < resolvedVideos.length; i2++) {
|
|
27989
28114
|
if (signal?.aborted) break;
|
|
27990
28115
|
const entry = resolvedVideos[i2];
|
|
@@ -27998,8 +28123,8 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
|
|
|
27998
28123
|
const sourceRemaining = metadata.durationSeconds - entry.video.mediaStart;
|
|
27999
28124
|
segDuration = sourceRemaining > 0 ? sourceRemaining : metadata.durationSeconds;
|
|
28000
28125
|
}
|
|
28001
|
-
|
|
28002
|
-
const normalizedPath =
|
|
28126
|
+
mkdirSync15(vfrNormDir, { recursive: true });
|
|
28127
|
+
const normalizedPath = join26(vfrNormDir, `${entry.video.id}_cfr.mp4`);
|
|
28003
28128
|
try {
|
|
28004
28129
|
await convertVfrToCfr(
|
|
28005
28130
|
entry.videoPath,
|
|
@@ -28255,7 +28380,7 @@ var init_videoFrameExtractor = __esm({
|
|
|
28255
28380
|
cleanup() {
|
|
28256
28381
|
for (const video of this.videos.values()) {
|
|
28257
28382
|
if (video.extracted.ownedByLookup) continue;
|
|
28258
|
-
if (
|
|
28383
|
+
if (existsSync24(video.extracted.outputDir)) {
|
|
28259
28384
|
rmSync5(video.extracted.outputDir, { recursive: true, force: true });
|
|
28260
28385
|
}
|
|
28261
28386
|
}
|
|
@@ -28563,8 +28688,8 @@ var init_videoFrameInjector = __esm({
|
|
|
28563
28688
|
});
|
|
28564
28689
|
|
|
28565
28690
|
// ../engine/src/services/audioMixer.ts
|
|
28566
|
-
import { existsSync as
|
|
28567
|
-
import { isAbsolute as isAbsolute3, join as
|
|
28691
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync16, rmSync as rmSync6 } from "fs";
|
|
28692
|
+
import { isAbsolute as isAbsolute3, join as join27, dirname as dirname8 } from "path";
|
|
28568
28693
|
function parseAudioElements(html) {
|
|
28569
28694
|
const elements = [];
|
|
28570
28695
|
const { document: document2 } = parseHTML(unwrapTemplate(html));
|
|
@@ -28615,7 +28740,7 @@ function parseAudioElements(html) {
|
|
|
28615
28740
|
async function extractAudioFromVideo(videoPath, outputPath, options, signal, config) {
|
|
28616
28741
|
const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
|
|
28617
28742
|
const outputDir = dirname8(outputPath);
|
|
28618
|
-
if (!
|
|
28743
|
+
if (!existsSync25(outputDir)) mkdirSync16(outputDir, { recursive: true });
|
|
28619
28744
|
const args = ["-i", videoPath];
|
|
28620
28745
|
if (options?.startTime !== void 0) args.push("-ss", String(options.startTime));
|
|
28621
28746
|
if (options?.duration !== void 0) args.push("-t", String(options.duration));
|
|
@@ -28642,7 +28767,7 @@ async function extractAudioFromVideo(videoPath, outputPath, options, signal, con
|
|
|
28642
28767
|
async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, signal, config) {
|
|
28643
28768
|
const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
|
|
28644
28769
|
const outputDir = dirname8(outputPath);
|
|
28645
|
-
if (!
|
|
28770
|
+
if (!existsSync25(outputDir)) mkdirSync16(outputDir, { recursive: true });
|
|
28646
28771
|
const args = [
|
|
28647
28772
|
"-ss",
|
|
28648
28773
|
String(mediaStart),
|
|
@@ -28678,7 +28803,7 @@ async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, sign
|
|
|
28678
28803
|
async function generateSilence(outputPath, duration, signal, config) {
|
|
28679
28804
|
const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
|
|
28680
28805
|
const outputDir = dirname8(outputPath);
|
|
28681
|
-
if (!
|
|
28806
|
+
if (!existsSync25(outputDir)) mkdirSync16(outputDir, { recursive: true });
|
|
28682
28807
|
const args = [
|
|
28683
28808
|
"-f",
|
|
28684
28809
|
"lavfi",
|
|
@@ -28721,7 +28846,7 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config)
|
|
|
28721
28846
|
};
|
|
28722
28847
|
}
|
|
28723
28848
|
const outputDir = dirname8(outputPath);
|
|
28724
|
-
if (!
|
|
28849
|
+
if (!existsSync25(outputDir)) mkdirSync16(outputDir, { recursive: true });
|
|
28725
28850
|
const inputs = [];
|
|
28726
28851
|
const filterParts = [];
|
|
28727
28852
|
tracks.forEach((track, i2) => {
|
|
@@ -28782,7 +28907,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
28782
28907
|
const startMs = Date.now();
|
|
28783
28908
|
const tracks = [];
|
|
28784
28909
|
const errors = [];
|
|
28785
|
-
if (!
|
|
28910
|
+
if (!existsSync25(workDir)) mkdirSync16(workDir, { recursive: true });
|
|
28786
28911
|
await Promise.all(
|
|
28787
28912
|
elements.map(async (element) => {
|
|
28788
28913
|
if (signal?.aborted) {
|
|
@@ -28792,8 +28917,8 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
28792
28917
|
try {
|
|
28793
28918
|
let srcPath = element.src;
|
|
28794
28919
|
if (!isAbsolute3(srcPath) && !isHttpUrl(srcPath)) {
|
|
28795
|
-
const fromCompiled = compiledDir ?
|
|
28796
|
-
srcPath = fromCompiled &&
|
|
28920
|
+
const fromCompiled = compiledDir ? join27(compiledDir, srcPath) : null;
|
|
28921
|
+
srcPath = fromCompiled && existsSync25(fromCompiled) ? fromCompiled : join27(baseDir, srcPath);
|
|
28797
28922
|
}
|
|
28798
28923
|
if (isHttpUrl(srcPath)) {
|
|
28799
28924
|
try {
|
|
@@ -28805,7 +28930,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
28805
28930
|
return;
|
|
28806
28931
|
}
|
|
28807
28932
|
}
|
|
28808
|
-
if (!
|
|
28933
|
+
if (!existsSync25(srcPath)) {
|
|
28809
28934
|
errors.push(`Source not found: ${element.id} (${element.src})`);
|
|
28810
28935
|
return;
|
|
28811
28936
|
}
|
|
@@ -28816,7 +28941,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
28816
28941
|
}
|
|
28817
28942
|
let audioSrcPath = srcPath;
|
|
28818
28943
|
if (element.type === "video") {
|
|
28819
|
-
const extractedPath =
|
|
28944
|
+
const extractedPath = join27(workDir, `${element.id}-extracted.wav`);
|
|
28820
28945
|
const extractResult = await extractAudioFromVideo(
|
|
28821
28946
|
srcPath,
|
|
28822
28947
|
extractedPath,
|
|
@@ -28833,7 +28958,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
28833
28958
|
}
|
|
28834
28959
|
audioSrcPath = extractedPath;
|
|
28835
28960
|
} else {
|
|
28836
|
-
const trimmedPath =
|
|
28961
|
+
const trimmedPath = join27(workDir, `${element.id}-trimmed.wav`);
|
|
28837
28962
|
const prepResult = await prepareAudioTrack(
|
|
28838
28963
|
srcPath,
|
|
28839
28964
|
trimmedPath,
|
|
@@ -28887,9 +29012,9 @@ var init_audioMixer = __esm({
|
|
|
28887
29012
|
|
|
28888
29013
|
// ../engine/src/services/parallelCoordinator.ts
|
|
28889
29014
|
import { cpus as cpus2, freemem, totalmem as totalmem2 } from "os";
|
|
28890
|
-
import { existsSync as
|
|
29015
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync17, readdirSync as readdirSync11 } from "fs";
|
|
28891
29016
|
import { copyFile, rename } from "fs/promises";
|
|
28892
|
-
import { join as
|
|
29017
|
+
import { join as join28 } from "path";
|
|
28893
29018
|
function calculateOptimalWorkers(totalFrames, requested, config) {
|
|
28894
29019
|
const effectiveMaxWorkers = (() => {
|
|
28895
29020
|
const concurrency = config?.concurrency ?? DEFAULT_CONFIG2.concurrency;
|
|
@@ -28932,7 +29057,7 @@ function distributeFrames(totalFrames, workerCount, workDir) {
|
|
|
28932
29057
|
workerId: i2,
|
|
28933
29058
|
startFrame,
|
|
28934
29059
|
endFrame,
|
|
28935
|
-
outputDir:
|
|
29060
|
+
outputDir: join28(workDir, `worker-${i2}`)
|
|
28936
29061
|
});
|
|
28937
29062
|
}
|
|
28938
29063
|
return tasks;
|
|
@@ -28940,7 +29065,7 @@ function distributeFrames(totalFrames, workerCount, workDir) {
|
|
|
28940
29065
|
async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCaptureHook, signal, onFrameCaptured, onFrameBuffer, config) {
|
|
28941
29066
|
const startTime = Date.now();
|
|
28942
29067
|
let framesCaptured = 0;
|
|
28943
|
-
if (!
|
|
29068
|
+
if (!existsSync26(task.outputDir)) mkdirSync17(task.outputDir, { recursive: true });
|
|
28944
29069
|
let session = null;
|
|
28945
29070
|
let perf;
|
|
28946
29071
|
try {
|
|
@@ -29030,17 +29155,17 @@ async function executeParallelCapture(serverUrl, workDir, tasks, captureOptions,
|
|
|
29030
29155
|
return results;
|
|
29031
29156
|
}
|
|
29032
29157
|
async function mergeWorkerFrames(workDir, tasks, outputDir) {
|
|
29033
|
-
if (!
|
|
29158
|
+
if (!existsSync26(outputDir)) mkdirSync17(outputDir, { recursive: true });
|
|
29034
29159
|
let totalFrames = 0;
|
|
29035
29160
|
const sortedTasks = [...tasks].sort((a, b) => a.startFrame - b.startFrame);
|
|
29036
29161
|
for (const task of sortedTasks) {
|
|
29037
|
-
if (!
|
|
29162
|
+
if (!existsSync26(task.outputDir)) {
|
|
29038
29163
|
continue;
|
|
29039
29164
|
}
|
|
29040
29165
|
const files = readdirSync11(task.outputDir).filter((f3) => f3.startsWith("frame_") && (f3.endsWith(".jpg") || f3.endsWith(".png"))).sort();
|
|
29041
29166
|
const copyTasks = files.map(async (file) => {
|
|
29042
|
-
const sourcePath =
|
|
29043
|
-
const targetPath =
|
|
29167
|
+
const sourcePath = join28(task.outputDir, file);
|
|
29168
|
+
const targetPath = join28(outputDir, file);
|
|
29044
29169
|
try {
|
|
29045
29170
|
await rename(sourcePath, targetPath);
|
|
29046
29171
|
} catch {
|
|
@@ -29077,8 +29202,8 @@ var init_parallelCoordinator = __esm({
|
|
|
29077
29202
|
// ../engine/src/services/fileServer.ts
|
|
29078
29203
|
import { Hono as Hono2 } from "hono";
|
|
29079
29204
|
import { serve } from "@hono/node-server";
|
|
29080
|
-
import { readFileSync as
|
|
29081
|
-
import { join as
|
|
29205
|
+
import { readFileSync as readFileSync17, existsSync as existsSync27, statSync as statSync9 } from "fs";
|
|
29206
|
+
import { join as join29, extname as extname6 } from "path";
|
|
29082
29207
|
function stripEmbeddedRuntimeScripts(html) {
|
|
29083
29208
|
if (!html) return html;
|
|
29084
29209
|
const scriptRe = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
|
|
@@ -29147,22 +29272,22 @@ function createFileServer(options) {
|
|
|
29147
29272
|
let requestPath = c2.req.path;
|
|
29148
29273
|
if (requestPath === "/") requestPath = "/index.html";
|
|
29149
29274
|
const relativePath = requestPath.replace(/^\//, "");
|
|
29150
|
-
const compiledPath = compiledDir ?
|
|
29275
|
+
const compiledPath = compiledDir ? join29(compiledDir, relativePath) : null;
|
|
29151
29276
|
const hasCompiledFile = Boolean(
|
|
29152
|
-
compiledPath &&
|
|
29277
|
+
compiledPath && existsSync27(compiledPath) && statSync9(compiledPath).isFile()
|
|
29153
29278
|
);
|
|
29154
|
-
const filePath = hasCompiledFile ? compiledPath :
|
|
29155
|
-
if (!
|
|
29279
|
+
const filePath = hasCompiledFile ? compiledPath : join29(projectDir, relativePath);
|
|
29280
|
+
if (!existsSync27(filePath) || !statSync9(filePath).isFile()) {
|
|
29156
29281
|
return c2.text("Not found", 404);
|
|
29157
29282
|
}
|
|
29158
29283
|
const ext = extname6(filePath).toLowerCase();
|
|
29159
29284
|
const contentType = MIME_TYPES2[ext] || "application/octet-stream";
|
|
29160
29285
|
if (ext === ".html") {
|
|
29161
|
-
const rawHtml =
|
|
29286
|
+
const rawHtml = readFileSync17(filePath, "utf-8");
|
|
29162
29287
|
const html = relativePath === "index.html" ? injectScriptsIntoHtml(rawHtml, headScripts, bodyScripts, stripEmbeddedRuntime) : rawHtml;
|
|
29163
29288
|
return c2.text(html, 200, { "Content-Type": contentType });
|
|
29164
29289
|
}
|
|
29165
|
-
const content =
|
|
29290
|
+
const content = readFileSync17(filePath);
|
|
29166
29291
|
return new Response(content, {
|
|
29167
29292
|
status: 200,
|
|
29168
29293
|
headers: { "Content-Type": contentType }
|
|
@@ -30430,8 +30555,8 @@ var init_shaderTransitions = __esm({
|
|
|
30430
30555
|
});
|
|
30431
30556
|
|
|
30432
30557
|
// ../engine/src/services/hdrCapture.ts
|
|
30433
|
-
import { existsSync as
|
|
30434
|
-
import { join as
|
|
30558
|
+
import { existsSync as existsSync28, readdirSync as readdirSync12 } from "fs";
|
|
30559
|
+
import { join as join30 } from "path";
|
|
30435
30560
|
import { homedir as homedir7 } from "os";
|
|
30436
30561
|
function linearToPQ(L2) {
|
|
30437
30562
|
const Lp = Math.max(0, L2 * SDR_NITS / PQ_MAX_NITS);
|
|
@@ -30547,12 +30672,12 @@ function float16ToPqRgb(rawBuffer, bytesPerRow, width, height) {
|
|
|
30547
30672
|
return output;
|
|
30548
30673
|
}
|
|
30549
30674
|
function resolveHeadedChromePath() {
|
|
30550
|
-
const baseDir =
|
|
30551
|
-
if (!
|
|
30675
|
+
const baseDir = join30(homedir7(), ".cache", "puppeteer", "chrome");
|
|
30676
|
+
if (!existsSync28(baseDir)) return void 0;
|
|
30552
30677
|
const versions = readdirSync12(baseDir).sort().reverse();
|
|
30553
30678
|
for (const version of versions) {
|
|
30554
30679
|
const candidates = [
|
|
30555
|
-
|
|
30680
|
+
join30(
|
|
30556
30681
|
baseDir,
|
|
30557
30682
|
version,
|
|
30558
30683
|
"chrome-mac-arm64",
|
|
@@ -30561,7 +30686,7 @@ function resolveHeadedChromePath() {
|
|
|
30561
30686
|
"MacOS",
|
|
30562
30687
|
"Google Chrome for Testing"
|
|
30563
30688
|
),
|
|
30564
|
-
|
|
30689
|
+
join30(
|
|
30565
30690
|
baseDir,
|
|
30566
30691
|
version,
|
|
30567
30692
|
"chrome-mac-x64",
|
|
@@ -30570,11 +30695,11 @@ function resolveHeadedChromePath() {
|
|
|
30570
30695
|
"MacOS",
|
|
30571
30696
|
"Google Chrome for Testing"
|
|
30572
30697
|
),
|
|
30573
|
-
|
|
30574
|
-
|
|
30698
|
+
join30(baseDir, version, "chrome-linux64", "chrome"),
|
|
30699
|
+
join30(baseDir, version, "chrome-win64", "chrome.exe")
|
|
30575
30700
|
];
|
|
30576
30701
|
for (const binary of candidates) {
|
|
30577
|
-
if (
|
|
30702
|
+
if (existsSync28(binary)) return binary;
|
|
30578
30703
|
}
|
|
30579
30704
|
}
|
|
30580
30705
|
return void 0;
|
|
@@ -30846,8 +30971,8 @@ var init_staticGuard = __esm({
|
|
|
30846
30971
|
});
|
|
30847
30972
|
|
|
30848
30973
|
// ../core/src/compiler/htmlBundler.ts
|
|
30849
|
-
import { readFileSync as
|
|
30850
|
-
import { join as
|
|
30974
|
+
import { readFileSync as readFileSync18, existsSync as existsSync29 } from "fs";
|
|
30975
|
+
import { join as join31, resolve as resolve12, isAbsolute as isAbsolute4, sep as sep2 } from "path";
|
|
30851
30976
|
import { transformSync } from "esbuild";
|
|
30852
30977
|
function parseHTMLContent2(html) {
|
|
30853
30978
|
const trimmed = html.trimStart().toLowerCase();
|
|
@@ -30915,17 +31040,17 @@ function isRelativeUrl(url) {
|
|
|
30915
31040
|
return !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("//") && !url.startsWith("data:") && !isAbsolute4(url);
|
|
30916
31041
|
}
|
|
30917
31042
|
function safeReadFile(filePath) {
|
|
30918
|
-
if (!
|
|
31043
|
+
if (!existsSync29(filePath)) return null;
|
|
30919
31044
|
try {
|
|
30920
|
-
return
|
|
31045
|
+
return readFileSync18(filePath, "utf-8");
|
|
30921
31046
|
} catch {
|
|
30922
31047
|
return null;
|
|
30923
31048
|
}
|
|
30924
31049
|
}
|
|
30925
31050
|
function safeReadFileBuffer(filePath) {
|
|
30926
|
-
if (!
|
|
31051
|
+
if (!existsSync29(filePath)) return null;
|
|
30927
31052
|
try {
|
|
30928
|
-
return
|
|
31053
|
+
return readFileSync18(filePath);
|
|
30929
31054
|
} catch {
|
|
30930
31055
|
return null;
|
|
30931
31056
|
}
|
|
@@ -31116,9 +31241,9 @@ function stripJsCommentsParserSafe(source) {
|
|
|
31116
31241
|
}
|
|
31117
31242
|
}
|
|
31118
31243
|
async function bundleToSingleHtml(projectDir, options) {
|
|
31119
|
-
const indexPath =
|
|
31120
|
-
if (!
|
|
31121
|
-
const rawHtml =
|
|
31244
|
+
const indexPath = join31(projectDir, "index.html");
|
|
31245
|
+
if (!existsSync29(indexPath)) throw new Error("index.html not found in project directory");
|
|
31246
|
+
const rawHtml = readFileSync18(indexPath, "utf-8");
|
|
31122
31247
|
const compiled = await compileHtml(rawHtml, projectDir, options?.probeMediaDuration);
|
|
31123
31248
|
const staticGuard = validateHyperframeHtmlContract(compiled);
|
|
31124
31249
|
if (!staticGuard.isValid) {
|
|
@@ -31402,7 +31527,7 @@ var init_compiler = __esm({
|
|
|
31402
31527
|
|
|
31403
31528
|
// ../producer/src/services/hyperframeRuntimeLoader.ts
|
|
31404
31529
|
import { createHash as createHash3 } from "crypto";
|
|
31405
|
-
import { existsSync as
|
|
31530
|
+
import { existsSync as existsSync30, readFileSync as readFileSync19 } from "fs";
|
|
31406
31531
|
import { dirname as dirname9, resolve as resolve13 } from "path";
|
|
31407
31532
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
31408
31533
|
function resolveHyperframeManifestPath() {
|
|
@@ -31415,7 +31540,7 @@ function resolveHyperframeManifestPath() {
|
|
|
31415
31540
|
MODULE_RELATIVE_MANIFEST_PATH
|
|
31416
31541
|
];
|
|
31417
31542
|
for (const candidate of candidates) {
|
|
31418
|
-
if (
|
|
31543
|
+
if (existsSync30(candidate)) {
|
|
31419
31544
|
return candidate;
|
|
31420
31545
|
}
|
|
31421
31546
|
}
|
|
@@ -31426,12 +31551,12 @@ function getVerifiedHyperframeRuntimeSource() {
|
|
|
31426
31551
|
}
|
|
31427
31552
|
function resolveVerifiedHyperframeRuntime() {
|
|
31428
31553
|
const manifestPath = resolveHyperframeManifestPath();
|
|
31429
|
-
if (!
|
|
31554
|
+
if (!existsSync30(manifestPath)) {
|
|
31430
31555
|
throw new Error(
|
|
31431
31556
|
`[HyperframeRuntimeLoader] Missing manifest at ${manifestPath}. Build core runtime artifacts before rendering.`
|
|
31432
31557
|
);
|
|
31433
31558
|
}
|
|
31434
|
-
const manifestRaw =
|
|
31559
|
+
const manifestRaw = readFileSync19(manifestPath, "utf8");
|
|
31435
31560
|
const manifest = JSON.parse(manifestRaw);
|
|
31436
31561
|
const runtimeFileName = manifest.artifacts?.iife;
|
|
31437
31562
|
if (!runtimeFileName || !manifest.sha256) {
|
|
@@ -31440,10 +31565,10 @@ function resolveVerifiedHyperframeRuntime() {
|
|
|
31440
31565
|
);
|
|
31441
31566
|
}
|
|
31442
31567
|
const runtimePath = resolve13(dirname9(manifestPath), runtimeFileName);
|
|
31443
|
-
if (!
|
|
31568
|
+
if (!existsSync30(runtimePath)) {
|
|
31444
31569
|
throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
|
|
31445
31570
|
}
|
|
31446
|
-
const runtimeSource =
|
|
31571
|
+
const runtimeSource = readFileSync19(runtimePath, "utf8");
|
|
31447
31572
|
const runtimeSha = createHash3("sha256").update(runtimeSource, "utf8").digest("hex");
|
|
31448
31573
|
if (runtimeSha !== manifest.sha256) {
|
|
31449
31574
|
throw new Error(
|
|
@@ -31482,16 +31607,16 @@ var init_hyperframeRuntimeLoader = __esm({
|
|
|
31482
31607
|
// ../producer/src/services/fileServer.ts
|
|
31483
31608
|
import { Hono as Hono3 } from "hono";
|
|
31484
31609
|
import { serve as serve2 } from "@hono/node-server";
|
|
31485
|
-
import { readFileSync as
|
|
31486
|
-
import { join as
|
|
31610
|
+
import { readFileSync as readFileSync20, existsSync as existsSync31, realpathSync, statSync as statSync10 } from "fs";
|
|
31611
|
+
import { join as join32, extname as extname7, resolve as resolve14, sep as sep3 } from "path";
|
|
31487
31612
|
function isPathInside(child, parent, options = {}) {
|
|
31488
31613
|
const { resolveSymlinks = false, pathModule } = options;
|
|
31489
31614
|
const resolveFn = pathModule?.resolve ?? resolve14;
|
|
31490
31615
|
const separator = pathModule?.sep ?? sep3;
|
|
31491
31616
|
const resolvedChild = resolveFn(child);
|
|
31492
31617
|
const resolvedParent = resolveFn(parent);
|
|
31493
|
-
const normalizedChild = resolveSymlinks &&
|
|
31494
|
-
const normalizedParent = resolveSymlinks &&
|
|
31618
|
+
const normalizedChild = resolveSymlinks && existsSync31(resolvedChild) ? realpathSync.native(resolvedChild) : resolvedChild;
|
|
31619
|
+
const normalizedParent = resolveSymlinks && existsSync31(resolvedParent) ? realpathSync.native(resolvedParent) : resolvedParent;
|
|
31495
31620
|
if (normalizedChild === normalizedParent) return true;
|
|
31496
31621
|
const parentWithSep = normalizedParent.endsWith(separator) ? normalizedParent : normalizedParent + separator;
|
|
31497
31622
|
return normalizedChild.startsWith(parentWithSep);
|
|
@@ -31580,14 +31705,14 @@ function createFileServer2(options) {
|
|
|
31580
31705
|
const relativePath = requestPath.replace(/^\//, "");
|
|
31581
31706
|
let filePath = null;
|
|
31582
31707
|
if (compiledDir) {
|
|
31583
|
-
const candidate =
|
|
31584
|
-
if (
|
|
31708
|
+
const candidate = join32(compiledDir, relativePath);
|
|
31709
|
+
if (existsSync31(candidate) && isPathInside(candidate, compiledDir) && statSync10(candidate).isFile()) {
|
|
31585
31710
|
filePath = candidate;
|
|
31586
31711
|
}
|
|
31587
31712
|
}
|
|
31588
31713
|
if (!filePath) {
|
|
31589
|
-
const candidate =
|
|
31590
|
-
if (
|
|
31714
|
+
const candidate = join32(projectDir, relativePath);
|
|
31715
|
+
if (existsSync31(candidate) && isPathInside(candidate, projectDir) && statSync10(candidate).isFile()) {
|
|
31591
31716
|
filePath = candidate;
|
|
31592
31717
|
}
|
|
31593
31718
|
}
|
|
@@ -31600,7 +31725,7 @@ function createFileServer2(options) {
|
|
|
31600
31725
|
const ext = extname7(filePath).toLowerCase();
|
|
31601
31726
|
const contentType = MIME_TYPES3[ext] || "application/octet-stream";
|
|
31602
31727
|
if (ext === ".html") {
|
|
31603
|
-
const rawHtml =
|
|
31728
|
+
const rawHtml = readFileSync20(filePath, "utf-8");
|
|
31604
31729
|
const isIndex = relativePath === "index.html";
|
|
31605
31730
|
let html = rawHtml;
|
|
31606
31731
|
if (preHeadScripts.length > 0) {
|
|
@@ -31609,7 +31734,7 @@ function createFileServer2(options) {
|
|
|
31609
31734
|
html = isIndex ? injectScriptsIntoHtml2(html, headScripts, bodyScripts, stripEmbeddedRuntime) : html;
|
|
31610
31735
|
return c2.text(html, 200, { "Content-Type": contentType });
|
|
31611
31736
|
}
|
|
31612
|
-
const content =
|
|
31737
|
+
const content = readFileSync20(filePath);
|
|
31613
31738
|
return new Response(content, {
|
|
31614
31739
|
status: 200,
|
|
31615
31740
|
headers: { "Content-Type": contentType }
|
|
@@ -31961,7 +32086,7 @@ var init_ffprobe2 = __esm({
|
|
|
31961
32086
|
});
|
|
31962
32087
|
|
|
31963
32088
|
// ../producer/src/utils/paths.ts
|
|
31964
|
-
import { resolve as resolve15, basename as basename2, join as
|
|
32089
|
+
import { resolve as resolve15, basename as basename2, join as join33, relative as relative2, isAbsolute as isAbsolute5 } from "path";
|
|
31965
32090
|
function isPathInside2(childPath, parentPath) {
|
|
31966
32091
|
const absChild = resolve15(childPath);
|
|
31967
32092
|
const absParent = resolve15(parentPath);
|
|
@@ -31982,7 +32107,7 @@ function toExternalAssetKey(absPath) {
|
|
|
31982
32107
|
function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
|
|
31983
32108
|
const absoluteProjectDir = resolve15(projectDir);
|
|
31984
32109
|
const projectName = basename2(absoluteProjectDir);
|
|
31985
|
-
const resolvedOutputPath = outputPath ??
|
|
32110
|
+
const resolvedOutputPath = outputPath ?? join33(rendersDir, `${projectName}.mp4`);
|
|
31986
32111
|
const absoluteOutputPath = resolve15(resolvedOutputPath);
|
|
31987
32112
|
return { absoluteProjectDir, absoluteOutputPath };
|
|
31988
32113
|
}
|
|
@@ -32055,9 +32180,9 @@ var init_fontData_generated = __esm({
|
|
|
32055
32180
|
});
|
|
32056
32181
|
|
|
32057
32182
|
// ../producer/src/services/deterministicFonts.ts
|
|
32058
|
-
import { existsSync as
|
|
32183
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync18, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
|
|
32059
32184
|
import { homedir as homedir8 } from "os";
|
|
32060
|
-
import { join as
|
|
32185
|
+
import { join as join34 } from "path";
|
|
32061
32186
|
function normalizeFamilyName(family) {
|
|
32062
32187
|
return family.trim().replace(/^['"]|['"]$/g, "").trim().toLowerCase();
|
|
32063
32188
|
}
|
|
@@ -32168,14 +32293,14 @@ function fontSlug(familyName) {
|
|
|
32168
32293
|
return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
32169
32294
|
}
|
|
32170
32295
|
function fontCacheDir(slug) {
|
|
32171
|
-
const dir =
|
|
32172
|
-
if (!
|
|
32173
|
-
|
|
32296
|
+
const dir = join34(GOOGLE_FONTS_CACHE_DIR, slug);
|
|
32297
|
+
if (!existsSync32(dir)) {
|
|
32298
|
+
mkdirSync18(dir, { recursive: true });
|
|
32174
32299
|
}
|
|
32175
32300
|
return dir;
|
|
32176
32301
|
}
|
|
32177
32302
|
function cachedWoff2Path(slug, weight, style) {
|
|
32178
|
-
return
|
|
32303
|
+
return join34(fontCacheDir(slug), `${weight}-${style}.woff2`);
|
|
32179
32304
|
}
|
|
32180
32305
|
async function fetchGoogleFont(familyName) {
|
|
32181
32306
|
const slug = fontSlug(familyName);
|
|
@@ -32201,17 +32326,17 @@ async function fetchGoogleFont(familyName) {
|
|
|
32201
32326
|
const woff2Url = match[3] || "";
|
|
32202
32327
|
if (!woff2Url) continue;
|
|
32203
32328
|
const cachePath2 = cachedWoff2Path(slug, weight, style);
|
|
32204
|
-
if (!
|
|
32329
|
+
if (!existsSync32(cachePath2)) {
|
|
32205
32330
|
try {
|
|
32206
32331
|
const fontRes = await fetch(woff2Url);
|
|
32207
32332
|
if (!fontRes.ok) continue;
|
|
32208
32333
|
const buffer = Buffer.from(await fontRes.arrayBuffer());
|
|
32209
|
-
|
|
32334
|
+
writeFileSync13(cachePath2, buffer);
|
|
32210
32335
|
} catch {
|
|
32211
32336
|
continue;
|
|
32212
32337
|
}
|
|
32213
32338
|
}
|
|
32214
|
-
const fontBytes =
|
|
32339
|
+
const fontBytes = readFileSync21(cachePath2);
|
|
32215
32340
|
const dataUri = `data:font/woff2;base64,${fontBytes.toString("base64")}`;
|
|
32216
32341
|
faces.push({ weight, style, dataUri });
|
|
32217
32342
|
}
|
|
@@ -32387,14 +32512,14 @@ var init_deterministicFonts = __esm({
|
|
|
32387
32512
|
poppins: "poppins",
|
|
32388
32513
|
"segoe ui": "roboto"
|
|
32389
32514
|
};
|
|
32390
|
-
GOOGLE_FONTS_CACHE_DIR =
|
|
32515
|
+
GOOGLE_FONTS_CACHE_DIR = join34(homedir8(), ".cache", "hyperframes", "fonts");
|
|
32391
32516
|
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";
|
|
32392
32517
|
}
|
|
32393
32518
|
});
|
|
32394
32519
|
|
|
32395
32520
|
// ../producer/src/services/htmlCompiler.ts
|
|
32396
|
-
import { readFileSync as
|
|
32397
|
-
import { join as
|
|
32521
|
+
import { readFileSync as readFileSync22, existsSync as existsSync33, mkdirSync as mkdirSync19 } from "fs";
|
|
32522
|
+
import { join as join35, dirname as dirname10, resolve as resolve16 } from "path";
|
|
32398
32523
|
import postcss from "postcss";
|
|
32399
32524
|
function dedupeElementsById(elements) {
|
|
32400
32525
|
const deduped = /* @__PURE__ */ new Map();
|
|
@@ -32445,16 +32570,16 @@ function detectRenderModeHints(html) {
|
|
|
32445
32570
|
async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagName19) {
|
|
32446
32571
|
let filePath = src;
|
|
32447
32572
|
if (isHttpUrl(src)) {
|
|
32448
|
-
if (!
|
|
32573
|
+
if (!existsSync33(downloadDir)) mkdirSync19(downloadDir, { recursive: true });
|
|
32449
32574
|
try {
|
|
32450
32575
|
filePath = await downloadToTemp(src, downloadDir);
|
|
32451
32576
|
} catch {
|
|
32452
32577
|
return { duration: 0, resolvedPath: src };
|
|
32453
32578
|
}
|
|
32454
32579
|
} else if (!filePath.startsWith("/")) {
|
|
32455
|
-
filePath =
|
|
32580
|
+
filePath = join35(baseDir, filePath);
|
|
32456
32581
|
}
|
|
32457
|
-
if (!
|
|
32582
|
+
if (!existsSync33(filePath)) {
|
|
32458
32583
|
return { duration: 0, resolvedPath: filePath };
|
|
32459
32584
|
}
|
|
32460
32585
|
const metadata = tagName19 === "video" ? await extractMediaMetadata(filePath) : await extractAudioMetadata(filePath);
|
|
@@ -32523,10 +32648,10 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
|
|
|
32523
32648
|
if (visited.has(filePath)) {
|
|
32524
32649
|
continue;
|
|
32525
32650
|
}
|
|
32526
|
-
if (!
|
|
32651
|
+
if (!existsSync33(filePath)) {
|
|
32527
32652
|
continue;
|
|
32528
32653
|
}
|
|
32529
|
-
const rawSubHtml =
|
|
32654
|
+
const rawSubHtml = readFileSync22(filePath, "utf-8");
|
|
32530
32655
|
const nestedVisited = new Set(visited);
|
|
32531
32656
|
nestedVisited.add(filePath);
|
|
32532
32657
|
workItems.push({ srcPath, absoluteStart, absoluteEnd, filePath, rawSubHtml, nestedVisited });
|
|
@@ -32733,8 +32858,8 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
|
|
|
32733
32858
|
let compHtml = subCompositions.get(srcPath) || null;
|
|
32734
32859
|
if (!compHtml) {
|
|
32735
32860
|
const filePath = resolve16(projectDir, srcPath);
|
|
32736
|
-
if (
|
|
32737
|
-
compHtml =
|
|
32861
|
+
if (existsSync33(filePath)) {
|
|
32862
|
+
compHtml = readFileSync22(filePath, "utf-8");
|
|
32738
32863
|
}
|
|
32739
32864
|
}
|
|
32740
32865
|
if (!compHtml) {
|
|
@@ -32961,7 +33086,7 @@ function collectExternalAssets(html, projectDir) {
|
|
|
32961
33086
|
if (isPathInside2(absPath, absProjectDir)) {
|
|
32962
33087
|
return null;
|
|
32963
33088
|
}
|
|
32964
|
-
if (!
|
|
33089
|
+
if (!existsSync33(absPath)) return null;
|
|
32965
33090
|
const safeKey = toExternalAssetKey(absPath);
|
|
32966
33091
|
externalAssets.set(safeKey, absPath);
|
|
32967
33092
|
return safeKey;
|
|
@@ -33006,7 +33131,7 @@ function collectExternalAssets(html, projectDir) {
|
|
|
33006
33131
|
};
|
|
33007
33132
|
}
|
|
33008
33133
|
async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
33009
|
-
const rawHtml =
|
|
33134
|
+
const rawHtml = readFileSync22(htmlPath, "utf-8");
|
|
33010
33135
|
const { html: compiledHtml, unresolvedCompositions } = await compileHtmlFile(
|
|
33011
33136
|
rawHtml,
|
|
33012
33137
|
projectDir,
|
|
@@ -33346,17 +33471,17 @@ var init_hdrImageTransferCache = __esm({
|
|
|
33346
33471
|
|
|
33347
33472
|
// ../producer/src/services/renderOrchestrator.ts
|
|
33348
33473
|
import {
|
|
33349
|
-
existsSync as
|
|
33350
|
-
mkdirSync as
|
|
33474
|
+
existsSync as existsSync34,
|
|
33475
|
+
mkdirSync as mkdirSync20,
|
|
33351
33476
|
rmSync as rmSync7,
|
|
33352
|
-
readFileSync as
|
|
33477
|
+
readFileSync as readFileSync23,
|
|
33353
33478
|
readdirSync as readdirSync14,
|
|
33354
33479
|
statSync as statSync11,
|
|
33355
|
-
writeFileSync as
|
|
33480
|
+
writeFileSync as writeFileSync14,
|
|
33356
33481
|
copyFileSync as copyFileSync2,
|
|
33357
33482
|
appendFileSync
|
|
33358
33483
|
} from "fs";
|
|
33359
|
-
import { join as
|
|
33484
|
+
import { join as join36, dirname as dirname11, resolve as resolve17 } from "path";
|
|
33360
33485
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
33361
33486
|
import { freemem as freemem2 } from "os";
|
|
33362
33487
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -33382,7 +33507,7 @@ function sampleDirectoryBytes(dir) {
|
|
|
33382
33507
|
continue;
|
|
33383
33508
|
}
|
|
33384
33509
|
for (const name of entries2) {
|
|
33385
|
-
const full =
|
|
33510
|
+
const full = join36(current, name);
|
|
33386
33511
|
try {
|
|
33387
33512
|
const st2 = statSync11(full);
|
|
33388
33513
|
if (st2.isDirectory()) {
|
|
@@ -33457,21 +33582,21 @@ function installDebugLogger(logPath, log2 = defaultLogger) {
|
|
|
33457
33582
|
};
|
|
33458
33583
|
}
|
|
33459
33584
|
function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
33460
|
-
const compileDir =
|
|
33461
|
-
|
|
33462
|
-
|
|
33585
|
+
const compileDir = join36(workDir, "compiled");
|
|
33586
|
+
mkdirSync20(compileDir, { recursive: true });
|
|
33587
|
+
writeFileSync14(join36(compileDir, "index.html"), compiled.html, "utf-8");
|
|
33463
33588
|
for (const [srcPath, html] of compiled.subCompositions) {
|
|
33464
|
-
const outPath =
|
|
33465
|
-
|
|
33466
|
-
|
|
33589
|
+
const outPath = join36(compileDir, srcPath);
|
|
33590
|
+
mkdirSync20(dirname11(outPath), { recursive: true });
|
|
33591
|
+
writeFileSync14(outPath, html, "utf-8");
|
|
33467
33592
|
}
|
|
33468
33593
|
for (const [relativePath, absolutePath] of compiled.externalAssets) {
|
|
33469
|
-
const outPath = resolve17(
|
|
33594
|
+
const outPath = resolve17(join36(compileDir, relativePath));
|
|
33470
33595
|
if (!isPathInside2(outPath, compileDir)) {
|
|
33471
33596
|
console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
|
|
33472
33597
|
continue;
|
|
33473
33598
|
}
|
|
33474
|
-
|
|
33599
|
+
mkdirSync20(dirname11(outPath), { recursive: true });
|
|
33475
33600
|
copyFileSync2(absolutePath, outPath);
|
|
33476
33601
|
}
|
|
33477
33602
|
if (includeSummary) {
|
|
@@ -33496,7 +33621,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
|
|
|
33496
33621
|
subCompositions: Array.from(compiled.subCompositions.keys()),
|
|
33497
33622
|
renderModeHints: compiled.renderModeHints
|
|
33498
33623
|
};
|
|
33499
|
-
|
|
33624
|
+
writeFileSync14(join36(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
|
|
33500
33625
|
}
|
|
33501
33626
|
}
|
|
33502
33627
|
function applyRenderModeHints(cfg, compiled, log2 = defaultLogger) {
|
|
@@ -33517,12 +33642,12 @@ function blitHdrVideoLayer(canvas, el, time, fps, hdrFrameDirs, hdrStartTimes, w
|
|
|
33517
33642
|
if (videoFrameIndex < 1) return;
|
|
33518
33643
|
const maxIndex = getMaxFrameIndex(frameDir);
|
|
33519
33644
|
const effectiveIndex = maxIndex > 0 ? Math.min(videoFrameIndex, maxIndex) : videoFrameIndex;
|
|
33520
|
-
const framePath =
|
|
33521
|
-
if (!
|
|
33645
|
+
const framePath = join36(frameDir, `frame_${String(effectiveIndex).padStart(4, "0")}.png`);
|
|
33646
|
+
if (!existsSync34(framePath)) {
|
|
33522
33647
|
return;
|
|
33523
33648
|
}
|
|
33524
33649
|
try {
|
|
33525
|
-
const { data: hdrRgb, width: srcW, height: srcH } = decodePngToRgb48le(
|
|
33650
|
+
const { data: hdrRgb, width: srcW, height: srcH } = decodePngToRgb48le(readFileSync23(framePath));
|
|
33526
33651
|
if (sourceTransfer && targetTransfer && sourceTransfer !== targetTransfer) {
|
|
33527
33652
|
convertTransfer(hdrRgb, sourceTransfer, targetTransfer);
|
|
33528
33653
|
}
|
|
@@ -33701,7 +33826,7 @@ async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter,
|
|
|
33701
33826
|
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
33702
33827
|
const localTime = time - startTime;
|
|
33703
33828
|
const frameNum = Math.floor(localTime * fps) + 1;
|
|
33704
|
-
const expectedFrame = frameDir ?
|
|
33829
|
+
const expectedFrame = frameDir ? join36(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
33705
33830
|
log2.info("[diag] hdr layer blit", {
|
|
33706
33831
|
frame: debugFrameIndex,
|
|
33707
33832
|
layerIdx,
|
|
@@ -33713,7 +33838,7 @@ async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter,
|
|
|
33713
33838
|
localTime: localTime.toFixed(3),
|
|
33714
33839
|
hdrFrameNum: frameNum,
|
|
33715
33840
|
expectedFrame,
|
|
33716
|
-
expectedFrameExists: expectedFrame ?
|
|
33841
|
+
expectedFrameExists: expectedFrame ? existsSync34(expectedFrame) : false
|
|
33717
33842
|
});
|
|
33718
33843
|
}
|
|
33719
33844
|
}
|
|
@@ -33738,8 +33863,8 @@ async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter,
|
|
|
33738
33863
|
if (shouldLog && debugDumpDir) {
|
|
33739
33864
|
const after2 = countNonZeroRgb48(canvas);
|
|
33740
33865
|
const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
|
|
33741
|
-
const dumpPath =
|
|
33742
|
-
|
|
33866
|
+
const dumpPath = join36(debugDumpDir, dumpName);
|
|
33867
|
+
writeFileSync14(dumpPath, domPng);
|
|
33743
33868
|
log2.info("[diag] dom layer blit", {
|
|
33744
33869
|
frame: debugFrameIndex,
|
|
33745
33870
|
layerIdx,
|
|
@@ -33812,8 +33937,8 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
|
|
|
33812
33937
|
async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
|
|
33813
33938
|
const moduleDir = dirname11(fileURLToPath3(import.meta.url));
|
|
33814
33939
|
const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve17(process.env.PRODUCER_RENDERS_DIR, "..") : resolve17(moduleDir, "../..");
|
|
33815
|
-
const debugDir =
|
|
33816
|
-
const workDir = job.config.debug ?
|
|
33940
|
+
const debugDir = join36(producerRoot, ".debug");
|
|
33941
|
+
const workDir = job.config.debug ? join36(debugDir, job.id) : join36(dirname11(outputPath), `work-${job.id}`);
|
|
33817
33942
|
const pipelineStart = Date.now();
|
|
33818
33943
|
const log2 = job.config.logger ?? defaultLogger;
|
|
33819
33944
|
let fileServer = null;
|
|
@@ -33825,7 +33950,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
33825
33950
|
videoExtractionFailures: 0,
|
|
33826
33951
|
imageDecodeFailures: 0
|
|
33827
33952
|
};
|
|
33828
|
-
const perfOutputPath =
|
|
33953
|
+
const perfOutputPath = join36(workDir, "perf-summary.json");
|
|
33829
33954
|
const cfg = { ...job.config.producerConfig ?? resolveConfig() };
|
|
33830
33955
|
const outputFormat = job.config.format ?? "mp4";
|
|
33831
33956
|
const isWebm = outputFormat === "webm";
|
|
@@ -33858,28 +33983,28 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
33858
33983
|
};
|
|
33859
33984
|
job.startedAt = /* @__PURE__ */ new Date();
|
|
33860
33985
|
assertNotAborted();
|
|
33861
|
-
if (!
|
|
33986
|
+
if (!existsSync34(workDir)) mkdirSync20(workDir, { recursive: true });
|
|
33862
33987
|
if (job.config.debug) {
|
|
33863
|
-
const logPath =
|
|
33988
|
+
const logPath = join36(workDir, "render.log");
|
|
33864
33989
|
restoreLogger = installDebugLogger(logPath, log2);
|
|
33865
33990
|
}
|
|
33866
33991
|
const entryFile = job.config.entryFile || "index.html";
|
|
33867
|
-
let htmlPath =
|
|
33868
|
-
if (!
|
|
33992
|
+
let htmlPath = join36(projectDir, entryFile);
|
|
33993
|
+
if (!existsSync34(htmlPath)) {
|
|
33869
33994
|
throw new Error(`Entry file not found: ${htmlPath}`);
|
|
33870
33995
|
}
|
|
33871
33996
|
assertNotAborted();
|
|
33872
|
-
const rawEntry =
|
|
33997
|
+
const rawEntry = readFileSync23(htmlPath, "utf-8");
|
|
33873
33998
|
if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
|
|
33874
|
-
const wrapperPath =
|
|
33875
|
-
const projectIndexPath =
|
|
33876
|
-
if (!
|
|
33999
|
+
const wrapperPath = join36(workDir, "standalone-entry.html");
|
|
34000
|
+
const projectIndexPath = join36(projectDir, "index.html");
|
|
34001
|
+
if (!existsSync34(projectIndexPath)) {
|
|
33877
34002
|
throw new Error(
|
|
33878
34003
|
`Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
|
|
33879
34004
|
);
|
|
33880
34005
|
}
|
|
33881
34006
|
const standaloneHtml = extractStandaloneEntryFromIndex(
|
|
33882
|
-
|
|
34007
|
+
readFileSync23(projectIndexPath, "utf-8"),
|
|
33883
34008
|
entryFile
|
|
33884
34009
|
);
|
|
33885
34010
|
if (!standaloneHtml) {
|
|
@@ -33887,7 +34012,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
33887
34012
|
`Entry file "${entryFile}" is not mounted from index.html via data-composition-src, so it cannot be rendered independently.`
|
|
33888
34013
|
);
|
|
33889
34014
|
}
|
|
33890
|
-
|
|
34015
|
+
writeFileSync14(wrapperPath, standaloneHtml, "utf-8");
|
|
33891
34016
|
htmlPath = wrapperPath;
|
|
33892
34017
|
log2.info("Extracted standalone entry from index.html host context", {
|
|
33893
34018
|
entryFile
|
|
@@ -33896,7 +34021,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
33896
34021
|
const stage1Start = Date.now();
|
|
33897
34022
|
updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
|
|
33898
34023
|
const compileStart = Date.now();
|
|
33899
|
-
let compiled = await compileForRender(projectDir, htmlPath,
|
|
34024
|
+
let compiled = await compileForRender(projectDir, htmlPath, join36(workDir, "downloads"));
|
|
33900
34025
|
assertNotAborted();
|
|
33901
34026
|
perfStages.compileOnlyMs = Date.now() - compileStart;
|
|
33902
34027
|
applyRenderModeHints(cfg, compiled, log2);
|
|
@@ -33928,7 +34053,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
33928
34053
|
reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
|
|
33929
34054
|
fileServer = await createFileServer2({
|
|
33930
34055
|
projectDir,
|
|
33931
|
-
compiledDir:
|
|
34056
|
+
compiledDir: join36(workDir, "compiled"),
|
|
33932
34057
|
port: 0,
|
|
33933
34058
|
preHeadScripts: [VIRTUAL_TIME_SHIM]
|
|
33934
34059
|
});
|
|
@@ -33942,7 +34067,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
33942
34067
|
};
|
|
33943
34068
|
probeSession = await createCaptureSession(
|
|
33944
34069
|
fileServer.url,
|
|
33945
|
-
|
|
34070
|
+
join36(workDir, "probe"),
|
|
33946
34071
|
captureOpts,
|
|
33947
34072
|
null,
|
|
33948
34073
|
cfg
|
|
@@ -33974,7 +34099,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
33974
34099
|
compiled,
|
|
33975
34100
|
resolutions,
|
|
33976
34101
|
projectDir,
|
|
33977
|
-
|
|
34102
|
+
join36(workDir, "downloads")
|
|
33978
34103
|
);
|
|
33979
34104
|
assertNotAborted();
|
|
33980
34105
|
composition.videos = compiled.videos;
|
|
@@ -34128,7 +34253,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34128
34253
|
const stage2Start = Date.now();
|
|
34129
34254
|
updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
|
|
34130
34255
|
let frameLookup = null;
|
|
34131
|
-
const compiledDir =
|
|
34256
|
+
const compiledDir = join36(workDir, "compiled");
|
|
34132
34257
|
let extractionResult = null;
|
|
34133
34258
|
const nativeHdrVideoIds = /* @__PURE__ */ new Set();
|
|
34134
34259
|
const videoTransfers = /* @__PURE__ */ new Map();
|
|
@@ -34137,10 +34262,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34137
34262
|
composition.videos.map(async (v) => {
|
|
34138
34263
|
let videoPath = v.src;
|
|
34139
34264
|
if (!videoPath.startsWith("/")) {
|
|
34140
|
-
const fromCompiled =
|
|
34265
|
+
const fromCompiled = existsSync34(join36(compiledDir, videoPath)) ? join36(compiledDir, videoPath) : join36(projectDir, videoPath);
|
|
34141
34266
|
videoPath = fromCompiled;
|
|
34142
34267
|
}
|
|
34143
|
-
if (!
|
|
34268
|
+
if (!existsSync34(videoPath)) return;
|
|
34144
34269
|
const meta = await extractMediaMetadata(videoPath);
|
|
34145
34270
|
if (isHdrColorSpace(meta.colorSpace)) {
|
|
34146
34271
|
nativeHdrVideoIds.add(v.id);
|
|
@@ -34158,10 +34283,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34158
34283
|
composition.images.map(async (img) => {
|
|
34159
34284
|
let imgPath = img.src;
|
|
34160
34285
|
if (!imgPath.startsWith("/")) {
|
|
34161
|
-
const fromCompiled =
|
|
34286
|
+
const fromCompiled = existsSync34(join36(compiledDir, imgPath)) ? join36(compiledDir, imgPath) : join36(projectDir, imgPath);
|
|
34162
34287
|
imgPath = fromCompiled;
|
|
34163
34288
|
}
|
|
34164
|
-
if (!
|
|
34289
|
+
if (!existsSync34(imgPath)) return null;
|
|
34165
34290
|
const meta = await extractMediaMetadata(imgPath);
|
|
34166
34291
|
if (isHdrColorSpace(meta.colorSpace)) {
|
|
34167
34292
|
nativeHdrImageIds.add(img.id);
|
|
@@ -34177,7 +34302,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34177
34302
|
extractionResult = await extractAllVideoFrames(
|
|
34178
34303
|
composition.videos,
|
|
34179
34304
|
projectDir,
|
|
34180
|
-
{ fps: job.config.fps, outputDir:
|
|
34305
|
+
{ fps: job.config.fps, outputDir: join36(workDir, "video-frames") },
|
|
34181
34306
|
abortSignal,
|
|
34182
34307
|
{ extractCacheDir: cfg.extractCacheDir },
|
|
34183
34308
|
compiledDir
|
|
@@ -34235,13 +34360,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34235
34360
|
}
|
|
34236
34361
|
const stage3Start = Date.now();
|
|
34237
34362
|
updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
|
|
34238
|
-
const audioOutputPath =
|
|
34363
|
+
const audioOutputPath = join36(workDir, "audio.aac");
|
|
34239
34364
|
let hasAudio = false;
|
|
34240
34365
|
if (composition.audios.length > 0) {
|
|
34241
34366
|
const audioResult = await processCompositionAudio(
|
|
34242
34367
|
composition.audios,
|
|
34243
34368
|
projectDir,
|
|
34244
|
-
|
|
34369
|
+
join36(workDir, "audio-work"),
|
|
34245
34370
|
audioOutputPath,
|
|
34246
34371
|
job.duration,
|
|
34247
34372
|
abortSignal,
|
|
@@ -34259,14 +34384,14 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34259
34384
|
if (!fileServer) {
|
|
34260
34385
|
fileServer = await createFileServer2({
|
|
34261
34386
|
projectDir,
|
|
34262
|
-
compiledDir:
|
|
34387
|
+
compiledDir: join36(workDir, "compiled"),
|
|
34263
34388
|
port: 0,
|
|
34264
34389
|
preHeadScripts: [VIRTUAL_TIME_SHIM]
|
|
34265
34390
|
});
|
|
34266
34391
|
assertNotAborted();
|
|
34267
34392
|
}
|
|
34268
|
-
const framesDir =
|
|
34269
|
-
if (!
|
|
34393
|
+
const framesDir = join36(workDir, "captured-frames");
|
|
34394
|
+
if (!existsSync34(framesDir)) mkdirSync20(framesDir, { recursive: true });
|
|
34270
34395
|
const captureOptions = {
|
|
34271
34396
|
width,
|
|
34272
34397
|
height,
|
|
@@ -34281,7 +34406,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34281
34406
|
const workerCount = calculateOptimalWorkers(totalFrames, job.config.workers, cfg);
|
|
34282
34407
|
const FORMAT_EXT2 = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
34283
34408
|
const videoExt = FORMAT_EXT2[outputFormat] ?? ".mp4";
|
|
34284
|
-
const videoOnlyPath =
|
|
34409
|
+
const videoOnlyPath = join36(workDir, `video-only${videoExt}`);
|
|
34285
34410
|
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
34286
34411
|
const hasHdrContent = effectiveHdr && nativeHdrIds.size > 0;
|
|
34287
34412
|
const encoderHdr = hasHdrContent ? effectiveHdr : void 0;
|
|
@@ -34303,8 +34428,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34303
34428
|
if (!hdrVideoIds.includes(v.id)) continue;
|
|
34304
34429
|
let srcPath = v.src;
|
|
34305
34430
|
if (!srcPath.startsWith("/")) {
|
|
34306
|
-
const fromCompiled =
|
|
34307
|
-
srcPath =
|
|
34431
|
+
const fromCompiled = join36(compiledDir, srcPath);
|
|
34432
|
+
srcPath = existsSync34(fromCompiled) ? fromCompiled : join36(projectDir, srcPath);
|
|
34308
34433
|
}
|
|
34309
34434
|
hdrVideoSrcPaths.set(v.id, srcPath);
|
|
34310
34435
|
}
|
|
@@ -34434,8 +34559,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34434
34559
|
for (const [videoId, srcPath] of hdrVideoSrcPaths) {
|
|
34435
34560
|
const video = composition.videos.find((v) => v.id === videoId);
|
|
34436
34561
|
if (!video) continue;
|
|
34437
|
-
const frameDir =
|
|
34438
|
-
|
|
34562
|
+
const frameDir = join36(framesDir, `hdr_${videoId}`);
|
|
34563
|
+
mkdirSync20(frameDir, { recursive: true });
|
|
34439
34564
|
const duration = video.end - video.start;
|
|
34440
34565
|
const dims = hdrExtractionDims.get(videoId) ?? { width, height };
|
|
34441
34566
|
const ffmpegArgs = [
|
|
@@ -34454,7 +34579,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34454
34579
|
"-c:v",
|
|
34455
34580
|
"png",
|
|
34456
34581
|
"-y",
|
|
34457
|
-
|
|
34582
|
+
join36(frameDir, "frame_%04d.png")
|
|
34458
34583
|
];
|
|
34459
34584
|
const result = await runFfmpeg(ffmpegArgs, { signal: abortSignal });
|
|
34460
34585
|
if (!result.success) {
|
|
@@ -34473,7 +34598,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34473
34598
|
const hdrImageBuffers = /* @__PURE__ */ new Map();
|
|
34474
34599
|
for (const [imageId, srcPath] of hdrImageSrcPaths) {
|
|
34475
34600
|
try {
|
|
34476
|
-
const decoded = decodePngToRgb48le(
|
|
34601
|
+
const decoded = decodePngToRgb48le(readFileSync23(srcPath));
|
|
34477
34602
|
const layout2 = hdrExtractionDims.get(imageId);
|
|
34478
34603
|
const fitInfo = hdrImageFitInfo.get(imageId);
|
|
34479
34604
|
if (layout2 && (layout2.width !== decoded.width || layout2.height !== decoded.height)) {
|
|
@@ -34522,9 +34647,9 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34522
34647
|
}
|
|
34523
34648
|
}
|
|
34524
34649
|
const debugDumpEnabled = process.env.KEEP_TEMP === "1";
|
|
34525
|
-
const debugDumpDir = debugDumpEnabled ?
|
|
34526
|
-
if (debugDumpDir && !
|
|
34527
|
-
|
|
34650
|
+
const debugDumpDir = debugDumpEnabled ? join36(framesDir, "debug-composite") : null;
|
|
34651
|
+
if (debugDumpDir && !existsSync34(debugDumpDir)) {
|
|
34652
|
+
mkdirSync20(debugDumpDir, { recursive: true });
|
|
34528
34653
|
}
|
|
34529
34654
|
if (!effectiveHdr) {
|
|
34530
34655
|
throw new Error(
|
|
@@ -34670,11 +34795,11 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
34670
34795
|
i2
|
|
34671
34796
|
);
|
|
34672
34797
|
if (debugDumpEnabled && debugDumpDir && i2 % 30 === 0) {
|
|
34673
|
-
const previewPath =
|
|
34798
|
+
const previewPath = join36(
|
|
34674
34799
|
debugDumpDir,
|
|
34675
34800
|
`frame_${String(i2).padStart(4, "0")}_final_rgb48le.bin`
|
|
34676
34801
|
);
|
|
34677
|
-
|
|
34802
|
+
writeFileSync14(previewPath, normalCanvas);
|
|
34678
34803
|
}
|
|
34679
34804
|
hdrEncoder.writeFrame(normalCanvas);
|
|
34680
34805
|
}
|
|
@@ -35017,7 +35142,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35017
35142
|
updateJobStatus(job, "complete", "Render complete", 100, onProgress);
|
|
35018
35143
|
const totalElapsed = Date.now() - pipelineStart;
|
|
35019
35144
|
sampleMemory();
|
|
35020
|
-
const tmpPeakBytes =
|
|
35145
|
+
const tmpPeakBytes = existsSync34(workDir) ? sampleDirectoryBytes(workDir) : 0;
|
|
35021
35146
|
const perfSummary = {
|
|
35022
35147
|
renderId: job.id,
|
|
35023
35148
|
totalElapsedMs: totalElapsed,
|
|
@@ -35042,7 +35167,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35042
35167
|
job.perfSummary = perfSummary;
|
|
35043
35168
|
if (job.config.debug) {
|
|
35044
35169
|
try {
|
|
35045
|
-
|
|
35170
|
+
writeFileSync14(perfOutputPath, JSON.stringify(perfSummary, null, 2), "utf-8");
|
|
35046
35171
|
} catch (err) {
|
|
35047
35172
|
log2.debug("Failed to write perf summary", {
|
|
35048
35173
|
perfOutputPath,
|
|
@@ -35051,8 +35176,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35051
35176
|
}
|
|
35052
35177
|
}
|
|
35053
35178
|
if (job.config.debug) {
|
|
35054
|
-
if (
|
|
35055
|
-
const debugOutput =
|
|
35179
|
+
if (existsSync34(outputPath)) {
|
|
35180
|
+
const debugOutput = join36(workDir, `output${videoExt}`);
|
|
35056
35181
|
copyFileSync2(outputPath, debugOutput);
|
|
35057
35182
|
}
|
|
35058
35183
|
} else if (process.env.KEEP_TEMP === "1") {
|
|
@@ -35138,7 +35263,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
35138
35263
|
await safeCleanup(
|
|
35139
35264
|
"remove workDir (error)",
|
|
35140
35265
|
() => {
|
|
35141
|
-
if (
|
|
35266
|
+
if (existsSync34(workDir)) rmSync7(workDir, { recursive: true, force: true });
|
|
35142
35267
|
},
|
|
35143
35268
|
log2
|
|
35144
35269
|
);
|
|
@@ -35198,8 +35323,8 @@ var init_config3 = __esm({
|
|
|
35198
35323
|
});
|
|
35199
35324
|
|
|
35200
35325
|
// ../producer/src/services/hyperframeLint.ts
|
|
35201
|
-
import { existsSync as
|
|
35202
|
-
import { resolve as resolve18, join as
|
|
35326
|
+
import { existsSync as existsSync35, readFileSync as readFileSync24, statSync as statSync12 } from "fs";
|
|
35327
|
+
import { resolve as resolve18, join as join37 } from "path";
|
|
35203
35328
|
function isStringRecord(value) {
|
|
35204
35329
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
35205
35330
|
return false;
|
|
@@ -35227,7 +35352,7 @@ function pickEntryFile(files, preferredEntryFile) {
|
|
|
35227
35352
|
}
|
|
35228
35353
|
function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
35229
35354
|
const absProjectDir = resolve18(projectDir);
|
|
35230
|
-
if (!
|
|
35355
|
+
if (!existsSync35(absProjectDir) || !statSync12(absProjectDir).isDirectory()) {
|
|
35231
35356
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
35232
35357
|
}
|
|
35233
35358
|
const entryCandidates = [preferredEntryFile, "index.html", "src/index.html"].filter(
|
|
@@ -35238,16 +35363,16 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
35238
35363
|
if (!absoluteEntryPath.startsWith(absProjectDir)) {
|
|
35239
35364
|
return { error: `Entry file must stay inside project directory: ${entryFile}` };
|
|
35240
35365
|
}
|
|
35241
|
-
if (
|
|
35366
|
+
if (existsSync35(absoluteEntryPath) && statSync12(absoluteEntryPath).isFile()) {
|
|
35242
35367
|
return {
|
|
35243
35368
|
entryFile,
|
|
35244
|
-
html:
|
|
35369
|
+
html: readFileSync24(absoluteEntryPath, "utf-8"),
|
|
35245
35370
|
source: "projectDir"
|
|
35246
35371
|
};
|
|
35247
35372
|
}
|
|
35248
35373
|
}
|
|
35249
35374
|
return {
|
|
35250
|
-
error: `No HTML entry file found in project directory: ${
|
|
35375
|
+
error: `No HTML entry file found in project directory: ${join37(absProjectDir, preferredEntryFile || "index.html")}`
|
|
35251
35376
|
};
|
|
35252
35377
|
}
|
|
35253
35378
|
function prepareHyperframeLintBody(body) {
|
|
@@ -35335,15 +35460,15 @@ var init_semaphore = __esm({
|
|
|
35335
35460
|
|
|
35336
35461
|
// ../producer/src/server.ts
|
|
35337
35462
|
import {
|
|
35338
|
-
existsSync as
|
|
35339
|
-
mkdirSync as
|
|
35463
|
+
existsSync as existsSync36,
|
|
35464
|
+
mkdirSync as mkdirSync21,
|
|
35340
35465
|
statSync as statSync13,
|
|
35341
35466
|
mkdtempSync as mkdtempSync2,
|
|
35342
|
-
writeFileSync as
|
|
35467
|
+
writeFileSync as writeFileSync15,
|
|
35343
35468
|
rmSync as rmSync8,
|
|
35344
35469
|
createReadStream
|
|
35345
35470
|
} from "fs";
|
|
35346
|
-
import { resolve as resolve19, dirname as dirname12, join as
|
|
35471
|
+
import { resolve as resolve19, dirname as dirname12, join as join38 } from "path";
|
|
35347
35472
|
import { tmpdir as tmpdir3 } from "os";
|
|
35348
35473
|
import { parseArgs as parseArgs2 } from "util";
|
|
35349
35474
|
import crypto2 from "crypto";
|
|
@@ -35366,11 +35491,11 @@ async function prepareRenderBody(body) {
|
|
|
35366
35491
|
const projectDir = typeof body.projectDir === "string" ? body.projectDir : void 0;
|
|
35367
35492
|
if (projectDir) {
|
|
35368
35493
|
const absProjectDir = resolve19(projectDir);
|
|
35369
|
-
if (!
|
|
35494
|
+
if (!existsSync36(absProjectDir) || !statSync13(absProjectDir).isDirectory()) {
|
|
35370
35495
|
return { error: `Project directory not found: ${absProjectDir}` };
|
|
35371
35496
|
}
|
|
35372
35497
|
const entry = options.entryFile || "index.html";
|
|
35373
|
-
if (!
|
|
35498
|
+
if (!existsSync36(resolve19(absProjectDir, entry))) {
|
|
35374
35499
|
return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
|
|
35375
35500
|
}
|
|
35376
35501
|
return { prepared: { input: { projectDir: absProjectDir, ...options } } };
|
|
@@ -35395,8 +35520,8 @@ async function prepareRenderBody(body) {
|
|
|
35395
35520
|
}
|
|
35396
35521
|
}
|
|
35397
35522
|
const tempRoot = process.env.PRODUCER_TMP_PROJECT_DIR || tmpdir3();
|
|
35398
|
-
const tempProjectDir = mkdtempSync2(
|
|
35399
|
-
|
|
35523
|
+
const tempProjectDir = mkdtempSync2(join38(tempRoot, "producer-project-"));
|
|
35524
|
+
writeFileSync15(join38(tempProjectDir, "index.html"), htmlContent, "utf-8");
|
|
35400
35525
|
return {
|
|
35401
35526
|
prepared: {
|
|
35402
35527
|
input: {
|
|
@@ -35519,7 +35644,7 @@ function createRenderHandlers(options = {}) {
|
|
|
35519
35644
|
log2
|
|
35520
35645
|
);
|
|
35521
35646
|
const outputDir = dirname12(absoluteOutputPath);
|
|
35522
|
-
if (!
|
|
35647
|
+
if (!existsSync36(outputDir)) mkdirSync21(outputDir, { recursive: true });
|
|
35523
35648
|
const release2 = await renderSemaphore.acquire();
|
|
35524
35649
|
log2.info("render started", {
|
|
35525
35650
|
requestId,
|
|
@@ -35546,7 +35671,7 @@ function createRenderHandlers(options = {}) {
|
|
|
35546
35671
|
log2.info(`render progress ${pct}%`, { requestId, stage: j2.currentStage, message });
|
|
35547
35672
|
}
|
|
35548
35673
|
});
|
|
35549
|
-
const fileSize =
|
|
35674
|
+
const fileSize = existsSync36(absoluteOutputPath) ? statSync13(absoluteOutputPath).size : 0;
|
|
35550
35675
|
const durationMs = Date.now() - t0;
|
|
35551
35676
|
const outputToken = store.register(absoluteOutputPath);
|
|
35552
35677
|
const outputUrl = `${outputUrlPrefix}/${outputToken}`;
|
|
@@ -35630,7 +35755,7 @@ function createRenderHandlers(options = {}) {
|
|
|
35630
35755
|
log2
|
|
35631
35756
|
);
|
|
35632
35757
|
const outputDir = dirname12(absoluteOutputPath);
|
|
35633
|
-
if (!
|
|
35758
|
+
if (!existsSync36(outputDir)) mkdirSync21(outputDir, { recursive: true });
|
|
35634
35759
|
log2.info("render-stream started", { requestId, projectDir: input.projectDir });
|
|
35635
35760
|
const job = createRenderJob({
|
|
35636
35761
|
fps: input.fps,
|
|
@@ -35675,7 +35800,7 @@ function createRenderHandlers(options = {}) {
|
|
|
35675
35800
|
},
|
|
35676
35801
|
abortController.signal
|
|
35677
35802
|
);
|
|
35678
|
-
const fileSize =
|
|
35803
|
+
const fileSize = existsSync36(absoluteOutputPath) ? statSync13(absoluteOutputPath).size : 0;
|
|
35679
35804
|
const outputToken = store.register(absoluteOutputPath);
|
|
35680
35805
|
const outputUrl = `${outputUrlPrefix}/${outputToken}`;
|
|
35681
35806
|
log2.info("render-stream completed", { requestId, fileSize, perf: job.perfSummary ?? null });
|
|
@@ -35734,7 +35859,7 @@ function createRenderHandlers(options = {}) {
|
|
|
35734
35859
|
if (!artifact) {
|
|
35735
35860
|
return c2.json({ success: false, error: "Output artifact not found or expired" }, 404);
|
|
35736
35861
|
}
|
|
35737
|
-
if (!
|
|
35862
|
+
if (!existsSync36(artifact.path)) {
|
|
35738
35863
|
store.delete(token);
|
|
35739
35864
|
return c2.json({ success: false, error: "Output artifact file missing" }, 404);
|
|
35740
35865
|
}
|
|
@@ -35872,20 +35997,20 @@ __export(studioServer_exports, {
|
|
|
35872
35997
|
});
|
|
35873
35998
|
import { Hono as Hono5 } from "hono";
|
|
35874
35999
|
import { streamSSE as streamSSE3 } from "hono/streaming";
|
|
35875
|
-
import { existsSync as
|
|
35876
|
-
import { resolve as resolve20, join as
|
|
36000
|
+
import { existsSync as existsSync37, readFileSync as readFileSync25, writeFileSync as writeFileSync16, statSync as statSync14 } from "fs";
|
|
36001
|
+
import { resolve as resolve20, join as join39, basename as basename3 } from "path";
|
|
35877
36002
|
function resolveDistDir() {
|
|
35878
36003
|
return resolveStudioBundle().dir;
|
|
35879
36004
|
}
|
|
35880
36005
|
function resolveStudioBundle() {
|
|
35881
36006
|
const builtPath = resolve20(__dirname, "studio");
|
|
35882
36007
|
const builtIndex = resolve20(builtPath, "index.html");
|
|
35883
|
-
if (
|
|
36008
|
+
if (existsSync37(builtIndex)) {
|
|
35884
36009
|
return { dir: builtPath, indexPath: builtIndex, available: true, checkedPaths: [builtIndex] };
|
|
35885
36010
|
}
|
|
35886
36011
|
const devPath = resolve20(__dirname, "..", "..", "..", "studio", "dist");
|
|
35887
36012
|
const devIndex = resolve20(devPath, "index.html");
|
|
35888
|
-
if (
|
|
36013
|
+
if (existsSync37(devIndex)) {
|
|
35889
36014
|
return {
|
|
35890
36015
|
dir: devPath,
|
|
35891
36016
|
indexPath: devIndex,
|
|
@@ -35902,9 +36027,9 @@ function resolveStudioBundle() {
|
|
|
35902
36027
|
}
|
|
35903
36028
|
function resolveRuntimePath() {
|
|
35904
36029
|
const builtPath = resolve20(__dirname, "hyperframe-runtime.js");
|
|
35905
|
-
if (
|
|
36030
|
+
if (existsSync37(builtPath)) return builtPath;
|
|
35906
36031
|
const iifePath = resolve20(__dirname, "hyperframe.runtime.iife.js");
|
|
35907
|
-
if (
|
|
36032
|
+
if (existsSync37(iifePath)) return iifePath;
|
|
35908
36033
|
const devPath = resolve20(
|
|
35909
36034
|
__dirname,
|
|
35910
36035
|
"..",
|
|
@@ -35914,7 +36039,7 @@ function resolveRuntimePath() {
|
|
|
35914
36039
|
"dist",
|
|
35915
36040
|
"hyperframe.runtime.iife.js"
|
|
35916
36041
|
);
|
|
35917
|
-
if (
|
|
36042
|
+
if (existsSync37(devPath)) return devPath;
|
|
35918
36043
|
return builtPath;
|
|
35919
36044
|
}
|
|
35920
36045
|
async function getThumbnailBrowser() {
|
|
@@ -35976,7 +36101,7 @@ function createStudioServer(options) {
|
|
|
35976
36101
|
return lintHyperframeHtml2(html, opts);
|
|
35977
36102
|
},
|
|
35978
36103
|
runtimeUrl: "/api/runtime.js",
|
|
35979
|
-
rendersDir: () =>
|
|
36104
|
+
rendersDir: () => join39(projectDir, "renders"),
|
|
35980
36105
|
startRender(opts) {
|
|
35981
36106
|
const state = {
|
|
35982
36107
|
id: opts.jobId,
|
|
@@ -36009,7 +36134,7 @@ function createStudioServer(options) {
|
|
|
36009
36134
|
state.status = "complete";
|
|
36010
36135
|
state.progress = 100;
|
|
36011
36136
|
const metaPath = opts.outputPath.replace(/\.(mp4|webm|mov)$/, ".meta.json");
|
|
36012
|
-
|
|
36137
|
+
writeFileSync16(
|
|
36013
36138
|
metaPath,
|
|
36014
36139
|
JSON.stringify({ status: "complete", durationMs: Date.now() - startTime })
|
|
36015
36140
|
);
|
|
@@ -36018,7 +36143,7 @@ function createStudioServer(options) {
|
|
|
36018
36143
|
state.error = err instanceof Error ? err.message : String(err);
|
|
36019
36144
|
try {
|
|
36020
36145
|
const metaPath = opts.outputPath.replace(/\.(mp4|webm|mov)$/, ".meta.json");
|
|
36021
|
-
|
|
36146
|
+
writeFileSync16(metaPath, JSON.stringify({ status: "failed" }));
|
|
36022
36147
|
} catch {
|
|
36023
36148
|
}
|
|
36024
36149
|
}
|
|
@@ -36091,7 +36216,7 @@ function createStudioServer(options) {
|
|
|
36091
36216
|
});
|
|
36092
36217
|
app.get("/api/runtime.js", (c2) => {
|
|
36093
36218
|
const serve4 = async () => {
|
|
36094
|
-
const runtimeSource = await loadRuntimeSource() ?? (
|
|
36219
|
+
const runtimeSource = await loadRuntimeSource() ?? (existsSync37(runtimePath) ? readFileSync25(runtimePath, "utf-8") : null);
|
|
36095
36220
|
if (!runtimeSource) return c2.text("runtime not available", 404);
|
|
36096
36221
|
return c2.body(runtimeSource, 200, {
|
|
36097
36222
|
"Content-Type": "text/javascript",
|
|
@@ -36127,23 +36252,23 @@ function createStudioServer(options) {
|
|
|
36127
36252
|
});
|
|
36128
36253
|
app.get("/assets/*", (c2) => {
|
|
36129
36254
|
const filePath = resolve20(studioDir, c2.req.path.slice(1));
|
|
36130
|
-
if (!
|
|
36131
|
-
const content =
|
|
36255
|
+
if (!existsSync37(filePath) || !statSync14(filePath).isFile()) return c2.text("not found", 404);
|
|
36256
|
+
const content = readFileSync25(filePath);
|
|
36132
36257
|
return new Response(content, {
|
|
36133
36258
|
headers: { "Content-Type": getMimeType(filePath), "Cache-Control": "no-store" }
|
|
36134
36259
|
});
|
|
36135
36260
|
});
|
|
36136
36261
|
app.get("/icons/*", (c2) => {
|
|
36137
36262
|
const filePath = resolve20(studioDir, c2.req.path.slice(1));
|
|
36138
|
-
if (!
|
|
36139
|
-
const content =
|
|
36263
|
+
if (!existsSync37(filePath) || !statSync14(filePath).isFile()) return c2.text("not found", 404);
|
|
36264
|
+
const content = readFileSync25(filePath);
|
|
36140
36265
|
return new Response(content, {
|
|
36141
36266
|
headers: { "Content-Type": getMimeType(filePath), "Cache-Control": "no-store" }
|
|
36142
36267
|
});
|
|
36143
36268
|
});
|
|
36144
36269
|
app.get("*", (c2) => {
|
|
36145
36270
|
const indexPath = resolve20(studioDir, "index.html");
|
|
36146
|
-
if (!
|
|
36271
|
+
if (!existsSync37(indexPath)) {
|
|
36147
36272
|
return c2.html(
|
|
36148
36273
|
`<!doctype html>
|
|
36149
36274
|
<html>
|
|
@@ -36199,7 +36324,7 @@ function createStudioServer(options) {
|
|
|
36199
36324
|
500
|
|
36200
36325
|
);
|
|
36201
36326
|
}
|
|
36202
|
-
return c2.html(
|
|
36327
|
+
return c2.html(readFileSync25(indexPath, "utf-8"));
|
|
36203
36328
|
});
|
|
36204
36329
|
return { app, watcher };
|
|
36205
36330
|
}
|
|
@@ -36222,21 +36347,21 @@ __export(preview_exports, {
|
|
|
36222
36347
|
default: () => preview_default,
|
|
36223
36348
|
examples: () => examples
|
|
36224
36349
|
});
|
|
36225
|
-
import { spawn as
|
|
36226
|
-
import { existsSync as
|
|
36227
|
-
import { resolve as resolve21, dirname as dirname13, basename as basename4, join as
|
|
36350
|
+
import { spawn as spawn9 } from "child_process";
|
|
36351
|
+
import { existsSync as existsSync38, lstatSync, symlinkSync, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync22 } from "fs";
|
|
36352
|
+
import { resolve as resolve21, dirname as dirname13, basename as basename4, join as join40 } from "path";
|
|
36228
36353
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
36229
36354
|
import { createRequire } from "module";
|
|
36230
36355
|
async function runDevMode(dir, projectName) {
|
|
36231
36356
|
const thisFile = fileURLToPath4(import.meta.url);
|
|
36232
36357
|
const repoRoot = resolve21(dirname13(thisFile), "..", "..", "..", "..");
|
|
36233
|
-
const projectsDir =
|
|
36358
|
+
const projectsDir = join40(repoRoot, "packages", "studio", "data", "projects");
|
|
36234
36359
|
const pName = projectName ?? basename4(dir);
|
|
36235
|
-
const symlinkPath =
|
|
36236
|
-
|
|
36360
|
+
const symlinkPath = join40(projectsDir, pName);
|
|
36361
|
+
mkdirSync22(projectsDir, { recursive: true });
|
|
36237
36362
|
let createdSymlink = false;
|
|
36238
36363
|
if (dir !== symlinkPath) {
|
|
36239
|
-
if (
|
|
36364
|
+
if (existsSync38(symlinkPath)) {
|
|
36240
36365
|
try {
|
|
36241
36366
|
const stat3 = lstatSync(symlinkPath);
|
|
36242
36367
|
if (stat3.isSymbolicLink()) {
|
|
@@ -36248,7 +36373,7 @@ async function runDevMode(dir, projectName) {
|
|
|
36248
36373
|
} catch {
|
|
36249
36374
|
}
|
|
36250
36375
|
}
|
|
36251
|
-
if (!
|
|
36376
|
+
if (!existsSync38(symlinkPath)) {
|
|
36252
36377
|
symlinkSync(dir, symlinkPath, "dir");
|
|
36253
36378
|
createdSymlink = true;
|
|
36254
36379
|
}
|
|
@@ -36256,8 +36381,8 @@ async function runDevMode(dir, projectName) {
|
|
|
36256
36381
|
Wt2(c.bold("hyperframes preview"));
|
|
36257
36382
|
const s2 = be();
|
|
36258
36383
|
s2.start("Starting studio...");
|
|
36259
|
-
const studioPkgDir =
|
|
36260
|
-
const child =
|
|
36384
|
+
const studioPkgDir = join40(repoRoot, "packages", "studio");
|
|
36385
|
+
const child = spawn9("pnpm", ["exec", "vite"], {
|
|
36261
36386
|
cwd: studioPkgDir,
|
|
36262
36387
|
stdio: ["ignore", "pipe", "pipe"]
|
|
36263
36388
|
});
|
|
@@ -36290,7 +36415,7 @@ async function runDevMode(dir, projectName) {
|
|
|
36290
36415
|
if (createdSymlink) {
|
|
36291
36416
|
process.on("exit", () => {
|
|
36292
36417
|
try {
|
|
36293
|
-
if (
|
|
36418
|
+
if (existsSync38(symlinkPath)) unlinkSync5(symlinkPath);
|
|
36294
36419
|
} catch {
|
|
36295
36420
|
}
|
|
36296
36421
|
});
|
|
@@ -36301,7 +36426,7 @@ async function runDevMode(dir, projectName) {
|
|
|
36301
36426
|
}
|
|
36302
36427
|
function hasLocalStudio(dir) {
|
|
36303
36428
|
try {
|
|
36304
|
-
const req = createRequire(
|
|
36429
|
+
const req = createRequire(join40(dir, "package.json"));
|
|
36305
36430
|
req.resolve("@hyperframes/studio/package.json");
|
|
36306
36431
|
return true;
|
|
36307
36432
|
} catch {
|
|
@@ -36309,20 +36434,20 @@ function hasLocalStudio(dir) {
|
|
|
36309
36434
|
}
|
|
36310
36435
|
}
|
|
36311
36436
|
async function runLocalStudioMode(dir, projectName) {
|
|
36312
|
-
const req = createRequire(
|
|
36437
|
+
const req = createRequire(join40(dir, "package.json"));
|
|
36313
36438
|
const studioPkgPath = dirname13(req.resolve("@hyperframes/studio/package.json"));
|
|
36314
36439
|
const pName = projectName ?? basename4(dir);
|
|
36315
|
-
const projectsDir =
|
|
36316
|
-
const symlinkPath =
|
|
36317
|
-
|
|
36440
|
+
const projectsDir = join40(studioPkgPath, "data", "projects");
|
|
36441
|
+
const symlinkPath = join40(projectsDir, pName);
|
|
36442
|
+
mkdirSync22(projectsDir, { recursive: true });
|
|
36318
36443
|
let createdSymlink = false;
|
|
36319
36444
|
if (dir !== symlinkPath) {
|
|
36320
|
-
if (
|
|
36445
|
+
if (existsSync38(symlinkPath) && lstatSync(symlinkPath).isSymbolicLink()) {
|
|
36321
36446
|
if (resolve21(readlinkSync(symlinkPath)) !== resolve21(dir)) {
|
|
36322
36447
|
unlinkSync5(symlinkPath);
|
|
36323
36448
|
}
|
|
36324
36449
|
}
|
|
36325
|
-
if (!
|
|
36450
|
+
if (!existsSync38(symlinkPath)) {
|
|
36326
36451
|
symlinkSync(dir, symlinkPath, "dir");
|
|
36327
36452
|
createdSymlink = true;
|
|
36328
36453
|
}
|
|
@@ -36330,7 +36455,7 @@ async function runLocalStudioMode(dir, projectName) {
|
|
|
36330
36455
|
Wt2(c.bold("hyperframes preview") + c.dim(" (local studio)"));
|
|
36331
36456
|
const s2 = be();
|
|
36332
36457
|
s2.start("Starting studio...");
|
|
36333
|
-
const child =
|
|
36458
|
+
const child = spawn9("npx", ["vite"], {
|
|
36334
36459
|
cwd: studioPkgPath,
|
|
36335
36460
|
stdio: ["ignore", "pipe", "pipe"]
|
|
36336
36461
|
});
|
|
@@ -36361,7 +36486,7 @@ async function runLocalStudioMode(dir, projectName) {
|
|
|
36361
36486
|
if (createdSymlink) {
|
|
36362
36487
|
process.on("exit", () => {
|
|
36363
36488
|
try {
|
|
36364
|
-
if (
|
|
36489
|
+
if (existsSync38(symlinkPath)) unlinkSync5(symlinkPath);
|
|
36365
36490
|
} catch {
|
|
36366
36491
|
}
|
|
36367
36492
|
});
|
|
@@ -36537,8 +36662,8 @@ var init_preview2 = __esm({
|
|
|
36537
36662
|
const dir = resolve21(rawArg ?? ".");
|
|
36538
36663
|
const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
|
|
36539
36664
|
const projectName = isImplicitCwd ? basename4(process.env.PWD ?? dir) : basename4(dir);
|
|
36540
|
-
const indexPath =
|
|
36541
|
-
if (
|
|
36665
|
+
const indexPath = join40(dir, "index.html");
|
|
36666
|
+
if (existsSync38(indexPath)) {
|
|
36542
36667
|
const project = { dir, name: projectName, indexPath };
|
|
36543
36668
|
const lintResult = lintProject(project);
|
|
36544
36669
|
if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
|
|
@@ -36567,17 +36692,17 @@ __export(init_exports, {
|
|
|
36567
36692
|
examples: () => examples2
|
|
36568
36693
|
});
|
|
36569
36694
|
import {
|
|
36570
|
-
existsSync as
|
|
36571
|
-
mkdirSync as
|
|
36695
|
+
existsSync as existsSync39,
|
|
36696
|
+
mkdirSync as mkdirSync23,
|
|
36572
36697
|
copyFileSync as copyFileSync3,
|
|
36573
36698
|
cpSync,
|
|
36574
|
-
writeFileSync as
|
|
36575
|
-
readFileSync as
|
|
36699
|
+
writeFileSync as writeFileSync17,
|
|
36700
|
+
readFileSync as readFileSync26,
|
|
36576
36701
|
readdirSync as readdirSync15
|
|
36577
36702
|
} from "fs";
|
|
36578
|
-
import { resolve as resolve22, basename as basename5, join as
|
|
36703
|
+
import { resolve as resolve22, basename as basename5, join as join41, dirname as dirname14 } from "path";
|
|
36579
36704
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
36580
|
-
import { execFileSync as execFileSync5, spawn as
|
|
36705
|
+
import { execFileSync as execFileSync5, spawn as spawn10 } from "child_process";
|
|
36581
36706
|
function probeVideo(filePath) {
|
|
36582
36707
|
try {
|
|
36583
36708
|
const raw = execFileSync5(
|
|
@@ -36619,7 +36744,7 @@ function isWebCompatible(codec) {
|
|
|
36619
36744
|
}
|
|
36620
36745
|
function transcodeToMp4(inputPath, outputPath) {
|
|
36621
36746
|
return new Promise((resolvePromise) => {
|
|
36622
|
-
const child =
|
|
36747
|
+
const child = spawn10(
|
|
36623
36748
|
"ffmpeg",
|
|
36624
36749
|
[
|
|
36625
36750
|
"-i",
|
|
@@ -36647,7 +36772,7 @@ function resolveAssetDir(devSegments, builtSegments) {
|
|
|
36647
36772
|
const base = dirname14(fileURLToPath5(import.meta.url));
|
|
36648
36773
|
const devPath = resolve22(base, ...devSegments);
|
|
36649
36774
|
const builtPath = resolve22(base, ...builtSegments);
|
|
36650
|
-
return
|
|
36775
|
+
return existsSync39(devPath) ? devPath : builtPath;
|
|
36651
36776
|
}
|
|
36652
36777
|
function getStaticTemplateDir(templateId) {
|
|
36653
36778
|
return resolveAssetDir(["..", "templates", templateId], ["templates", templateId]);
|
|
@@ -36656,9 +36781,9 @@ function getSharedTemplateDir() {
|
|
|
36656
36781
|
return resolveAssetDir(["..", "templates", "_shared"], ["templates", "_shared"]);
|
|
36657
36782
|
}
|
|
36658
36783
|
function patchVideoSrc(dir, videoFilename, durationSeconds) {
|
|
36659
|
-
const htmlFiles = readdirSync15(dir, { withFileTypes: true, recursive: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".html")).map((e2) =>
|
|
36784
|
+
const htmlFiles = readdirSync15(dir, { withFileTypes: true, recursive: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".html")).map((e2) => join41(e2.parentPath ?? e2.path, e2.name));
|
|
36660
36785
|
for (const file of htmlFiles) {
|
|
36661
|
-
let content =
|
|
36786
|
+
let content = readFileSync26(file, "utf-8");
|
|
36662
36787
|
if (videoFilename) {
|
|
36663
36788
|
content = content.replaceAll("__VIDEO_SRC__", videoFilename);
|
|
36664
36789
|
} else {
|
|
@@ -36669,7 +36794,7 @@ function patchVideoSrc(dir, videoFilename, durationSeconds) {
|
|
|
36669
36794
|
}
|
|
36670
36795
|
const dur = durationSeconds ? String(Math.round(durationSeconds * 100) / 100) : "10";
|
|
36671
36796
|
content = content.replaceAll("__VIDEO_DURATION__", dur);
|
|
36672
|
-
|
|
36797
|
+
writeFileSync17(file, content, "utf-8");
|
|
36673
36798
|
}
|
|
36674
36799
|
}
|
|
36675
36800
|
async function patchTranscript(dir, transcriptPath) {
|
|
@@ -36761,15 +36886,15 @@ async function handleVideoFile(videoPath, destDir, interactive) {
|
|
|
36761
36886
|
return { meta, localVideoName };
|
|
36762
36887
|
}
|
|
36763
36888
|
async function scaffoldProject(destDir, name, templateId, localVideoName, durationSeconds) {
|
|
36764
|
-
|
|
36889
|
+
mkdirSync23(destDir, { recursive: true });
|
|
36765
36890
|
const templateDir = getStaticTemplateDir(templateId);
|
|
36766
|
-
if (
|
|
36891
|
+
if (existsSync39(templateDir)) {
|
|
36767
36892
|
cpSync(templateDir, destDir, { recursive: true });
|
|
36768
36893
|
} else {
|
|
36769
36894
|
await fetchRemoteTemplate(templateId, destDir);
|
|
36770
36895
|
}
|
|
36771
36896
|
patchVideoSrc(destDir, localVideoName, durationSeconds);
|
|
36772
|
-
|
|
36897
|
+
writeFileSync17(
|
|
36773
36898
|
resolve22(destDir, "meta.json"),
|
|
36774
36899
|
JSON.stringify(
|
|
36775
36900
|
{
|
|
@@ -36782,14 +36907,14 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
|
|
|
36782
36907
|
),
|
|
36783
36908
|
"utf-8"
|
|
36784
36909
|
);
|
|
36785
|
-
if (!
|
|
36910
|
+
if (!existsSync39(resolve22(destDir, "hyperframes.json"))) {
|
|
36786
36911
|
const { writeProjectConfig: writeProjectConfig2, DEFAULT_PROJECT_CONFIG: DEFAULT_PROJECT_CONFIG2 } = await Promise.resolve().then(() => (init_projectConfig(), projectConfig_exports));
|
|
36787
36912
|
writeProjectConfig2(destDir, DEFAULT_PROJECT_CONFIG2);
|
|
36788
36913
|
}
|
|
36789
36914
|
const sharedDir = getSharedTemplateDir();
|
|
36790
|
-
if (
|
|
36915
|
+
if (existsSync39(sharedDir)) {
|
|
36791
36916
|
for (const entry of readdirSync15(sharedDir, { withFileTypes: true })) {
|
|
36792
|
-
const src =
|
|
36917
|
+
const src = join41(sharedDir, entry.name);
|
|
36793
36918
|
const dest = resolve22(destDir, entry.name);
|
|
36794
36919
|
if (entry.isFile() || entry.isSymbolicLink()) {
|
|
36795
36920
|
copyFileSync3(src, dest);
|
|
@@ -36903,11 +37028,11 @@ var init_init = __esm({
|
|
|
36903
37028
|
const templateId2 = exampleFlag ?? "blank";
|
|
36904
37029
|
const name2 = args.name ?? "my-video";
|
|
36905
37030
|
const destDir2 = resolve22(name2);
|
|
36906
|
-
if (
|
|
37031
|
+
if (existsSync39(destDir2) && readdirSync15(destDir2).length > 0) {
|
|
36907
37032
|
console.error(c.error(`Directory already exists and is not empty: ${name2}`));
|
|
36908
37033
|
process.exit(1);
|
|
36909
37034
|
}
|
|
36910
|
-
|
|
37035
|
+
mkdirSync23(destDir2, { recursive: true });
|
|
36911
37036
|
let localVideoName2;
|
|
36912
37037
|
let videoDuration2;
|
|
36913
37038
|
let sourceFilePath2;
|
|
@@ -36917,7 +37042,7 @@ var init_init = __esm({
|
|
|
36917
37042
|
}
|
|
36918
37043
|
if (videoFlag) {
|
|
36919
37044
|
const videoPath = resolve22(videoFlag);
|
|
36920
|
-
if (!
|
|
37045
|
+
if (!existsSync39(videoPath)) {
|
|
36921
37046
|
console.error(c.error(`Video file not found: ${videoFlag}`));
|
|
36922
37047
|
process.exit(1);
|
|
36923
37048
|
}
|
|
@@ -36931,7 +37056,7 @@ var init_init = __esm({
|
|
|
36931
37056
|
}
|
|
36932
37057
|
if (audioFlag) {
|
|
36933
37058
|
const audioPath = resolve22(audioFlag);
|
|
36934
|
-
if (!
|
|
37059
|
+
if (!existsSync39(audioPath)) {
|
|
36935
37060
|
console.error(c.error(`Audio file not found: ${audioFlag}`));
|
|
36936
37061
|
process.exit(1);
|
|
36937
37062
|
}
|
|
@@ -36977,7 +37102,7 @@ var init_init = __esm({
|
|
|
36977
37102
|
}
|
|
36978
37103
|
trackInitTemplate(templateId2);
|
|
36979
37104
|
const transcriptFile2 = resolve22(destDir2, "transcript.json");
|
|
36980
|
-
if (
|
|
37105
|
+
if (existsSync39(transcriptFile2)) {
|
|
36981
37106
|
await patchTranscript(destDir2, transcriptFile2);
|
|
36982
37107
|
}
|
|
36983
37108
|
console.log(c.success(`Created ${c.accent(name2 + "/")}`));
|
|
@@ -37029,7 +37154,7 @@ var init_init = __esm({
|
|
|
37029
37154
|
name = nameResult;
|
|
37030
37155
|
}
|
|
37031
37156
|
const destDir = resolve22(name);
|
|
37032
|
-
if (
|
|
37157
|
+
if (existsSync39(destDir) && readdirSync15(destDir).length > 0) {
|
|
37033
37158
|
const overwrite = await Rt({
|
|
37034
37159
|
message: `Directory ${c.accent(name)} already exists and is not empty. Overwrite?`,
|
|
37035
37160
|
initialValue: false
|
|
@@ -37044,24 +37169,24 @@ var init_init = __esm({
|
|
|
37044
37169
|
let videoDuration;
|
|
37045
37170
|
if (videoFlag) {
|
|
37046
37171
|
const videoPath = resolve22(videoFlag);
|
|
37047
|
-
if (!
|
|
37172
|
+
if (!existsSync39(videoPath)) {
|
|
37048
37173
|
R2.error(`File not found: ${videoFlag}`);
|
|
37049
37174
|
Nt("Setup cancelled.");
|
|
37050
37175
|
process.exit(1);
|
|
37051
37176
|
}
|
|
37052
|
-
|
|
37177
|
+
mkdirSync23(destDir, { recursive: true });
|
|
37053
37178
|
sourceFilePath = videoPath;
|
|
37054
37179
|
const result = await handleVideoFile(videoPath, destDir, true);
|
|
37055
37180
|
localVideoName = result.localVideoName;
|
|
37056
37181
|
videoDuration = result.meta.durationSeconds;
|
|
37057
37182
|
} else if (audioFlag) {
|
|
37058
37183
|
const audioPath = resolve22(audioFlag);
|
|
37059
|
-
if (!
|
|
37184
|
+
if (!existsSync39(audioPath)) {
|
|
37060
37185
|
R2.error(`File not found: ${audioFlag}`);
|
|
37061
37186
|
Nt("Setup cancelled.");
|
|
37062
37187
|
process.exit(1);
|
|
37063
37188
|
}
|
|
37064
|
-
|
|
37189
|
+
mkdirSync23(destDir, { recursive: true });
|
|
37065
37190
|
sourceFilePath = audioPath;
|
|
37066
37191
|
copyFileSync3(audioPath, resolve22(destDir, basename5(audioPath)));
|
|
37067
37192
|
R2.info(`Audio copied to ${c.accent(basename5(audioPath))}`);
|
|
@@ -37149,7 +37274,7 @@ ${c.dim("Use --example blank for offline use.")}`
|
|
|
37149
37274
|
}
|
|
37150
37275
|
trackInitTemplate(templateId);
|
|
37151
37276
|
const transcriptFile = resolve22(destDir, "transcript.json");
|
|
37152
|
-
if (
|
|
37277
|
+
if (existsSync39(transcriptFile)) {
|
|
37153
37278
|
await patchTranscript(destDir, transcriptFile);
|
|
37154
37279
|
}
|
|
37155
37280
|
const files = readdirSync15(destDir);
|
|
@@ -37235,7 +37360,7 @@ __export(add_exports, {
|
|
|
37235
37360
|
remapTarget: () => remapTarget,
|
|
37236
37361
|
runAdd: () => runAdd
|
|
37237
37362
|
});
|
|
37238
|
-
import { existsSync as
|
|
37363
|
+
import { existsSync as existsSync40 } from "fs";
|
|
37239
37364
|
import { resolve as resolve23, relative as relative3 } from "path";
|
|
37240
37365
|
function remapTarget(item, originalTarget, paths) {
|
|
37241
37366
|
if (item.type === "hyperframes:block") {
|
|
@@ -37261,8 +37386,8 @@ function buildSnippet(item, relativeTarget) {
|
|
|
37261
37386
|
async function runAdd(opts) {
|
|
37262
37387
|
const projectDir = resolve23(opts.projectDir);
|
|
37263
37388
|
let config = loadProjectConfig(projectDir);
|
|
37264
|
-
const hasConfig =
|
|
37265
|
-
if (!hasConfig &&
|
|
37389
|
+
const hasConfig = existsSync40(projectConfigPath(projectDir));
|
|
37390
|
+
if (!hasConfig && existsSync40(resolve23(projectDir, "index.html"))) {
|
|
37266
37391
|
writeProjectConfig(projectDir, DEFAULT_PROJECT_CONFIG);
|
|
37267
37392
|
config = DEFAULT_PROJECT_CONFIG;
|
|
37268
37393
|
}
|
|
@@ -37361,10 +37486,10 @@ var init_add = __esm({
|
|
|
37361
37486
|
const projectDir = resolve23(args.dir ?? process.cwd());
|
|
37362
37487
|
const json = args.json === true;
|
|
37363
37488
|
const skipClipboard = args["no-clipboard"] === true;
|
|
37364
|
-
const hasConfigBefore =
|
|
37489
|
+
const hasConfigBefore = existsSync40(projectConfigPath(projectDir));
|
|
37365
37490
|
try {
|
|
37366
37491
|
const result = await runAdd({ name: args.name, projectDir, skipClipboard });
|
|
37367
|
-
const wroteConfig = !hasConfigBefore &&
|
|
37492
|
+
const wroteConfig = !hasConfigBefore && existsSync40(projectConfigPath(projectDir));
|
|
37368
37493
|
if (json) {
|
|
37369
37494
|
console.log(JSON.stringify(result));
|
|
37370
37495
|
return;
|
|
@@ -37574,17 +37699,17 @@ var init_format = __esm({
|
|
|
37574
37699
|
});
|
|
37575
37700
|
|
|
37576
37701
|
// src/utils/project.ts
|
|
37577
|
-
import { existsSync as
|
|
37702
|
+
import { existsSync as existsSync41, statSync as statSync15 } from "fs";
|
|
37578
37703
|
import { resolve as resolve25, basename as basename6 } from "path";
|
|
37579
37704
|
function resolveProject(dirArg) {
|
|
37580
37705
|
const dir = resolve25(dirArg ?? ".");
|
|
37581
37706
|
const name = basename6(dir);
|
|
37582
37707
|
const indexPath = resolve25(dir, "index.html");
|
|
37583
|
-
if (!
|
|
37708
|
+
if (!existsSync41(dir) || !statSync15(dir).isDirectory()) {
|
|
37584
37709
|
errorBox("Not a directory: " + dir);
|
|
37585
37710
|
process.exit(1);
|
|
37586
37711
|
}
|
|
37587
|
-
if (!
|
|
37712
|
+
if (!existsSync41(indexPath)) {
|
|
37588
37713
|
errorBox(
|
|
37589
37714
|
"No composition found in " + dir,
|
|
37590
37715
|
"No index.html file found.",
|
|
@@ -37607,7 +37732,7 @@ __export(play_exports, {
|
|
|
37607
37732
|
default: () => play_default,
|
|
37608
37733
|
examples: () => examples5
|
|
37609
37734
|
});
|
|
37610
|
-
import { existsSync as
|
|
37735
|
+
import { existsSync as existsSync42, readFileSync as readFileSync27 } from "fs";
|
|
37611
37736
|
import { resolve as resolve26, dirname as dirname15 } from "path";
|
|
37612
37737
|
function commandDir() {
|
|
37613
37738
|
return dirname15(new URL(import.meta.url).pathname);
|
|
@@ -37622,7 +37747,7 @@ function resolveRuntimePath2() {
|
|
|
37622
37747
|
resolve26(d, "..", "..", "..", "core", "dist", "hyperframe.runtime.iife.js")
|
|
37623
37748
|
];
|
|
37624
37749
|
for (const p of candidates) {
|
|
37625
|
-
if (
|
|
37750
|
+
if (existsSync42(p)) return p;
|
|
37626
37751
|
}
|
|
37627
37752
|
return null;
|
|
37628
37753
|
}
|
|
@@ -37636,7 +37761,7 @@ function resolvePlayerPath() {
|
|
|
37636
37761
|
resolve26(d, "..", "hyperframes-player.global.js")
|
|
37637
37762
|
];
|
|
37638
37763
|
for (const p of candidates) {
|
|
37639
|
-
if (
|
|
37764
|
+
if (existsSync42(p)) return p;
|
|
37640
37765
|
}
|
|
37641
37766
|
return null;
|
|
37642
37767
|
}
|
|
@@ -37723,13 +37848,13 @@ var init_play = __esm({
|
|
|
37723
37848
|
const { createAdaptorServer } = await import("@hono/node-server");
|
|
37724
37849
|
const app = new Hono6();
|
|
37725
37850
|
app.get("/player.js", (ctx) => {
|
|
37726
|
-
return ctx.body(
|
|
37851
|
+
return ctx.body(readFileSync27(playerPath, "utf-8"), 200, {
|
|
37727
37852
|
"Content-Type": "application/javascript",
|
|
37728
37853
|
"Cache-Control": "no-cache"
|
|
37729
37854
|
});
|
|
37730
37855
|
});
|
|
37731
37856
|
app.get("/runtime.js", (ctx) => {
|
|
37732
|
-
return ctx.body(
|
|
37857
|
+
return ctx.body(readFileSync27(runtimePath, "utf-8"), 200, {
|
|
37733
37858
|
"Content-Type": "application/javascript",
|
|
37734
37859
|
"Cache-Control": "no-cache"
|
|
37735
37860
|
});
|
|
@@ -37738,8 +37863,8 @@ var init_play = __esm({
|
|
|
37738
37863
|
const reqPath = ctx.req.path.replace("/composition/", "");
|
|
37739
37864
|
const filePath = resolve26(project.dir, reqPath);
|
|
37740
37865
|
if (!filePath.startsWith(project.dir)) return ctx.text("Forbidden", 403);
|
|
37741
|
-
if (!
|
|
37742
|
-
const content =
|
|
37866
|
+
if (!existsSync42(filePath)) return ctx.text("Not found", 404);
|
|
37867
|
+
const content = readFileSync27(filePath, "utf-8");
|
|
37743
37868
|
if (filePath.endsWith(".html")) {
|
|
37744
37869
|
const injected = injectRuntime(content);
|
|
37745
37870
|
return ctx.html(injected);
|
|
@@ -37758,7 +37883,7 @@ var init_play = __esm({
|
|
|
37758
37883
|
mp3: "audio/mpeg",
|
|
37759
37884
|
wav: "audio/wav"
|
|
37760
37885
|
};
|
|
37761
|
-
return ctx.body(
|
|
37886
|
+
return ctx.body(readFileSync27(filePath), 200, {
|
|
37762
37887
|
"Content-Type": types3[ext] ?? "application/octet-stream"
|
|
37763
37888
|
});
|
|
37764
37889
|
});
|
|
@@ -37814,16 +37939,99 @@ var init_play = __esm({
|
|
|
37814
37939
|
});
|
|
37815
37940
|
|
|
37816
37941
|
// src/utils/publishProject.ts
|
|
37817
|
-
import { basename as basename7, join as
|
|
37818
|
-
import { readdirSync as readdirSync16, readFileSync as
|
|
37942
|
+
import { basename as basename7, join as join42, relative as relative4 } from "path";
|
|
37943
|
+
import { readdirSync as readdirSync16, readFileSync as readFileSync28, statSync as statSync16 } from "fs";
|
|
37819
37944
|
import AdmZip from "adm-zip";
|
|
37945
|
+
function isRecord2(value) {
|
|
37946
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37947
|
+
}
|
|
37948
|
+
function dataRecord(payload) {
|
|
37949
|
+
if (!isRecord2(payload) || !isRecord2(payload["data"])) return null;
|
|
37950
|
+
return payload["data"];
|
|
37951
|
+
}
|
|
37952
|
+
function stringField(record, key2) {
|
|
37953
|
+
const value = record[key2];
|
|
37954
|
+
return typeof value === "string" ? value : null;
|
|
37955
|
+
}
|
|
37956
|
+
function parsePublishedProjectResponse(payload) {
|
|
37957
|
+
const data = dataRecord(payload);
|
|
37958
|
+
if (!data) return null;
|
|
37959
|
+
const projectId = stringField(data, "project_id");
|
|
37960
|
+
const title = stringField(data, "title");
|
|
37961
|
+
const url = stringField(data, "url");
|
|
37962
|
+
const claimToken = stringField(data, "claim_token");
|
|
37963
|
+
const fileCount = data["file_count"];
|
|
37964
|
+
if (!projectId || !title || !url || !claimToken || typeof fileCount !== "number") {
|
|
37965
|
+
return null;
|
|
37966
|
+
}
|
|
37967
|
+
return {
|
|
37968
|
+
projectId,
|
|
37969
|
+
title,
|
|
37970
|
+
fileCount,
|
|
37971
|
+
url,
|
|
37972
|
+
claimToken
|
|
37973
|
+
};
|
|
37974
|
+
}
|
|
37975
|
+
function parseStagedUploadResponse(payload, archiveByteLength) {
|
|
37976
|
+
const data = dataRecord(payload);
|
|
37977
|
+
if (!data) return null;
|
|
37978
|
+
const uploadUrl = stringField(data, "upload_url");
|
|
37979
|
+
const uploadKey = stringField(data, "upload_key");
|
|
37980
|
+
const contentType = stringField(data, "content_type") || PUBLISH_CONTENT_TYPE;
|
|
37981
|
+
if (!uploadUrl || !uploadKey) return null;
|
|
37982
|
+
return {
|
|
37983
|
+
uploadUrl,
|
|
37984
|
+
uploadKey,
|
|
37985
|
+
contentType,
|
|
37986
|
+
uploadHeaders: getUploadHeaders(data, uploadUrl, contentType, archiveByteLength)
|
|
37987
|
+
};
|
|
37988
|
+
}
|
|
37989
|
+
function getUploadHeaders(data, uploadUrl, contentType, archiveByteLength) {
|
|
37990
|
+
const headers = {};
|
|
37991
|
+
const uploadHeaders = data["upload_headers"];
|
|
37992
|
+
if (isRecord2(uploadHeaders)) {
|
|
37993
|
+
for (const [key2, value] of Object.entries(uploadHeaders)) {
|
|
37994
|
+
if (typeof value === "string" && key2.trim()) {
|
|
37995
|
+
headers[key2] = value;
|
|
37996
|
+
}
|
|
37997
|
+
}
|
|
37998
|
+
}
|
|
37999
|
+
if (!Object.keys(headers).some((key2) => key2.toLowerCase() === "content-type")) {
|
|
38000
|
+
headers["content-type"] = contentType;
|
|
38001
|
+
}
|
|
38002
|
+
const signedHeaders = new URL(uploadUrl).searchParams.get("X-Amz-SignedHeaders");
|
|
38003
|
+
if (signedHeaders?.split(";").includes("x-amz-server-side-encryption") && !Object.keys(headers).some((key2) => key2.toLowerCase() === "x-amz-server-side-encryption")) {
|
|
38004
|
+
headers["x-amz-server-side-encryption"] = "AES256";
|
|
38005
|
+
}
|
|
38006
|
+
if (signedHeaders?.split(";").includes("content-length") && !Object.keys(headers).some((key2) => key2.toLowerCase() === "content-length")) {
|
|
38007
|
+
headers["content-length"] = String(archiveByteLength);
|
|
38008
|
+
}
|
|
38009
|
+
return headers;
|
|
38010
|
+
}
|
|
38011
|
+
async function readJson(response) {
|
|
38012
|
+
return response.clone().json().catch(() => null);
|
|
38013
|
+
}
|
|
38014
|
+
async function readErrorMessage(response, fallback) {
|
|
38015
|
+
const contentType = response.headers.get("content-type") || "";
|
|
38016
|
+
if (contentType.includes("application/json")) {
|
|
38017
|
+
const payload = await readJson(response);
|
|
38018
|
+
if (isRecord2(payload) && typeof payload["message"] === "string") {
|
|
38019
|
+
return payload["message"];
|
|
38020
|
+
}
|
|
38021
|
+
}
|
|
38022
|
+
if (response.status === 403 && response.headers.get("cf-mitigated") === "challenge") {
|
|
38023
|
+
return "Publish upload was blocked before reaching HyperFrames. Please retry after staged uploads are available.";
|
|
38024
|
+
}
|
|
38025
|
+
const text = await response.text().catch(() => "");
|
|
38026
|
+
return text.trim() ? `${fallback}: ${text.trim().slice(0, 180)}` : fallback;
|
|
38027
|
+
}
|
|
37820
38028
|
function shouldIgnoreSegment(segment) {
|
|
37821
38029
|
return segment.startsWith(".") || IGNORED_DIRS.has(segment) || IGNORED_FILES.has(segment);
|
|
37822
38030
|
}
|
|
37823
38031
|
function collectProjectFiles(rootDir, currentDir, paths) {
|
|
37824
38032
|
for (const entry of readdirSync16(currentDir, { withFileTypes: true })) {
|
|
37825
38033
|
if (shouldIgnoreSegment(entry.name)) continue;
|
|
37826
|
-
const absolutePath =
|
|
38034
|
+
const absolutePath = join42(currentDir, entry.name);
|
|
37827
38035
|
const relativePath = relative4(rootDir, absolutePath).replaceAll("\\", "/");
|
|
37828
38036
|
if (!relativePath) continue;
|
|
37829
38037
|
if (entry.isDirectory()) {
|
|
@@ -37842,7 +38050,7 @@ function createPublishArchive(projectDir) {
|
|
|
37842
38050
|
}
|
|
37843
38051
|
const archive = new AdmZip();
|
|
37844
38052
|
for (const filePath of filePaths) {
|
|
37845
|
-
archive.addFile(filePath,
|
|
38053
|
+
archive.addFile(filePath, readFileSync28(join42(projectDir, filePath)));
|
|
37846
38054
|
}
|
|
37847
38055
|
return {
|
|
37848
38056
|
buffer: archive.toBuffer(),
|
|
@@ -37852,42 +38060,102 @@ function createPublishArchive(projectDir) {
|
|
|
37852
38060
|
function getPublishApiBaseUrl() {
|
|
37853
38061
|
return (process.env["HYPERFRAMES_PUBLISHED_PROJECTS_API_URL"] || process.env["HEYGEN_API_URL"] || "https://api2.heygen.com").replace(/\/$/, "");
|
|
37854
38062
|
}
|
|
37855
|
-
|
|
37856
|
-
const
|
|
37857
|
-
|
|
37858
|
-
|
|
37859
|
-
|
|
38063
|
+
function archiveArrayBuffer(archive) {
|
|
38064
|
+
const arrayBuffer = new ArrayBuffer(archive.buffer.byteLength);
|
|
38065
|
+
new Uint8Array(arrayBuffer).set(archive.buffer);
|
|
38066
|
+
return arrayBuffer;
|
|
38067
|
+
}
|
|
38068
|
+
async function publishProjectArchiveDirect(apiBaseUrl, title, archive) {
|
|
37860
38069
|
const body = new FormData();
|
|
37861
38070
|
body.set("title", title);
|
|
37862
|
-
body.set(
|
|
38071
|
+
body.set(
|
|
38072
|
+
"file",
|
|
38073
|
+
new File([archiveArrayBuffer(archive)], `${title}.zip`, { type: PUBLISH_CONTENT_TYPE })
|
|
38074
|
+
);
|
|
37863
38075
|
const headers = {
|
|
37864
38076
|
heygen_route: "canary"
|
|
37865
38077
|
};
|
|
37866
|
-
const response = await fetch(`${
|
|
38078
|
+
const response = await fetch(`${apiBaseUrl}/v1/hyperframes/projects/publish`, {
|
|
37867
38079
|
method: "POST",
|
|
37868
38080
|
body,
|
|
37869
38081
|
headers,
|
|
37870
|
-
signal: AbortSignal.timeout(
|
|
38082
|
+
signal: AbortSignal.timeout(PUBLISH_REQUEST_TIMEOUT_MS)
|
|
37871
38083
|
});
|
|
37872
|
-
const payload = await response
|
|
37873
|
-
const
|
|
37874
|
-
if (!response.ok || !
|
|
37875
|
-
throw new Error(
|
|
38084
|
+
const payload = await readJson(response);
|
|
38085
|
+
const publishedProject = parsePublishedProjectResponse(payload);
|
|
38086
|
+
if (!response.ok || !publishedProject) {
|
|
38087
|
+
throw new Error(await readErrorMessage(response, "Failed to publish project"));
|
|
37876
38088
|
}
|
|
37877
|
-
return
|
|
37878
|
-
|
|
37879
|
-
|
|
37880
|
-
|
|
37881
|
-
|
|
37882
|
-
|
|
37883
|
-
|
|
38089
|
+
return publishedProject;
|
|
38090
|
+
}
|
|
38091
|
+
async function publishProjectArchiveStaged(apiBaseUrl, title, archive) {
|
|
38092
|
+
const fileName = `${title}.zip`;
|
|
38093
|
+
const uploadResponse = await fetch(`${apiBaseUrl}/v1/hyperframes/projects/publish/upload`, {
|
|
38094
|
+
method: "POST",
|
|
38095
|
+
body: JSON.stringify({
|
|
38096
|
+
file_name: fileName,
|
|
38097
|
+
content_type: PUBLISH_CONTENT_TYPE,
|
|
38098
|
+
content_length: archive.buffer.byteLength
|
|
38099
|
+
}),
|
|
38100
|
+
headers: {
|
|
38101
|
+
"content-type": "application/json",
|
|
38102
|
+
heygen_route: "canary"
|
|
38103
|
+
},
|
|
38104
|
+
signal: AbortSignal.timeout(PUBLISH_REQUEST_TIMEOUT_MS)
|
|
38105
|
+
});
|
|
38106
|
+
if (uploadResponse.status === 404 || uploadResponse.status === 405) {
|
|
38107
|
+
return null;
|
|
38108
|
+
}
|
|
38109
|
+
const uploadPayload = await readJson(uploadResponse);
|
|
38110
|
+
const stagedUpload = parseStagedUploadResponse(uploadPayload, archive.buffer.byteLength);
|
|
38111
|
+
if (!uploadResponse.ok || !stagedUpload) {
|
|
38112
|
+
throw new Error(await readErrorMessage(uploadResponse, "Failed to prepare project upload"));
|
|
38113
|
+
}
|
|
38114
|
+
const s3Response = await fetch(stagedUpload.uploadUrl, {
|
|
38115
|
+
method: "PUT",
|
|
38116
|
+
body: new Blob([archiveArrayBuffer(archive)], { type: stagedUpload.contentType }),
|
|
38117
|
+
headers: stagedUpload.uploadHeaders,
|
|
38118
|
+
signal: AbortSignal.timeout(PUBLISH_REQUEST_TIMEOUT_MS)
|
|
38119
|
+
});
|
|
38120
|
+
if (!s3Response.ok) {
|
|
38121
|
+
throw new Error(await readErrorMessage(s3Response, "Failed to upload project archive"));
|
|
38122
|
+
}
|
|
38123
|
+
const completeResponse = await fetch(`${apiBaseUrl}/v1/hyperframes/projects/publish/complete`, {
|
|
38124
|
+
method: "POST",
|
|
38125
|
+
body: JSON.stringify({
|
|
38126
|
+
upload_key: stagedUpload.uploadKey,
|
|
38127
|
+
file_name: fileName,
|
|
38128
|
+
title
|
|
38129
|
+
}),
|
|
38130
|
+
headers: {
|
|
38131
|
+
"content-type": "application/json",
|
|
38132
|
+
heygen_route: "canary"
|
|
38133
|
+
},
|
|
38134
|
+
signal: AbortSignal.timeout(PUBLISH_REQUEST_TIMEOUT_MS)
|
|
38135
|
+
});
|
|
38136
|
+
const completePayload = await readJson(completeResponse);
|
|
38137
|
+
const publishedProject = parsePublishedProjectResponse(completePayload);
|
|
38138
|
+
if (!completeResponse.ok || !publishedProject) {
|
|
38139
|
+
throw new Error(await readErrorMessage(completeResponse, "Failed to publish project"));
|
|
38140
|
+
}
|
|
38141
|
+
return publishedProject;
|
|
38142
|
+
}
|
|
38143
|
+
async function publishProjectArchive(projectDir) {
|
|
38144
|
+
const title = basename7(projectDir);
|
|
38145
|
+
const archive = createPublishArchive(projectDir);
|
|
38146
|
+
const apiBaseUrl = getPublishApiBaseUrl();
|
|
38147
|
+
const stagedResult = await publishProjectArchiveStaged(apiBaseUrl, title, archive);
|
|
38148
|
+
if (stagedResult) return stagedResult;
|
|
38149
|
+
return publishProjectArchiveDirect(apiBaseUrl, title, archive);
|
|
37884
38150
|
}
|
|
37885
|
-
var IGNORED_DIRS, IGNORED_FILES;
|
|
38151
|
+
var IGNORED_DIRS, IGNORED_FILES, PUBLISH_CONTENT_TYPE, PUBLISH_REQUEST_TIMEOUT_MS;
|
|
37886
38152
|
var init_publishProject = __esm({
|
|
37887
38153
|
"src/utils/publishProject.ts"() {
|
|
37888
38154
|
"use strict";
|
|
37889
38155
|
IGNORED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".next", "coverage"]);
|
|
37890
38156
|
IGNORED_FILES = /* @__PURE__ */ new Set([".DS_Store", "Thumbs.db"]);
|
|
38157
|
+
PUBLISH_CONTENT_TYPE = "application/zip";
|
|
38158
|
+
PUBLISH_REQUEST_TIMEOUT_MS = 3e4;
|
|
37891
38159
|
}
|
|
37892
38160
|
});
|
|
37893
38161
|
|
|
@@ -37898,8 +38166,8 @@ __export(publish_exports, {
|
|
|
37898
38166
|
examples: () => examples6
|
|
37899
38167
|
});
|
|
37900
38168
|
import { basename as basename8, resolve as resolve27 } from "path";
|
|
37901
|
-
import { existsSync as
|
|
37902
|
-
import { join as
|
|
38169
|
+
import { existsSync as existsSync43 } from "fs";
|
|
38170
|
+
import { join as join43 } from "path";
|
|
37903
38171
|
var examples6, publish_default;
|
|
37904
38172
|
var init_publish = __esm({
|
|
37905
38173
|
"src/commands/publish.ts"() {
|
|
@@ -37934,8 +38202,8 @@ var init_publish = __esm({
|
|
|
37934
38202
|
const dir = resolve27(rawArg ?? ".");
|
|
37935
38203
|
const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
|
|
37936
38204
|
const projectName = isImplicitCwd ? basename8(process.env["PWD"] ?? dir) : basename8(dir);
|
|
37937
|
-
const indexPath =
|
|
37938
|
-
if (
|
|
38205
|
+
const indexPath = join43(dir, "index.html");
|
|
38206
|
+
if (existsSync43(indexPath)) {
|
|
37939
38207
|
const lintResult = lintProject({ dir, name: projectName, indexPath });
|
|
37940
38208
|
if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
|
|
37941
38209
|
console.log();
|
|
@@ -38106,10 +38374,10 @@ __export(render_exports, {
|
|
|
38106
38374
|
default: () => render_default,
|
|
38107
38375
|
examples: () => examples7
|
|
38108
38376
|
});
|
|
38109
|
-
import { mkdirSync as
|
|
38377
|
+
import { mkdirSync as mkdirSync24, readFileSync as readFileSync29, statSync as statSync17, writeFileSync as writeFileSync18, rmSync as rmSync9 } from "fs";
|
|
38110
38378
|
import { cpus as cpus3, freemem as freemem3, tmpdir as tmpdir4 } from "os";
|
|
38111
|
-
import { resolve as resolve28, dirname as dirname16, join as
|
|
38112
|
-
import { execFileSync as execFileSync6, spawn as
|
|
38379
|
+
import { resolve as resolve28, dirname as dirname16, join as join44, basename as basename9 } from "path";
|
|
38380
|
+
import { execFileSync as execFileSync6, spawn as spawn11 } from "child_process";
|
|
38113
38381
|
function defaultWorkerCount() {
|
|
38114
38382
|
return Math.max(1, Math.min(Math.floor(CPU_CORE_COUNT * 3 / 4), 8));
|
|
38115
38383
|
}
|
|
@@ -38145,9 +38413,9 @@ function ensureDockerImage(version, quiet) {
|
|
|
38145
38413
|
}
|
|
38146
38414
|
if (!quiet) console.log(c.dim(` Building Docker image: ${tag}...`));
|
|
38147
38415
|
const dockerfilePath = resolveDockerfilePath();
|
|
38148
|
-
const tmpDir =
|
|
38149
|
-
|
|
38150
|
-
|
|
38416
|
+
const tmpDir = join44(tmpdir4(), `hyperframes-docker-${Date.now()}`);
|
|
38417
|
+
mkdirSync24(tmpDir, { recursive: true });
|
|
38418
|
+
writeFileSync18(join44(tmpDir, "Dockerfile"), readFileSync29(dockerfilePath));
|
|
38151
38419
|
try {
|
|
38152
38420
|
execFileSync6(
|
|
38153
38421
|
"docker",
|
|
@@ -38216,7 +38484,7 @@ async function renderDocker(projectDir, outputPath, options) {
|
|
|
38216
38484
|
}
|
|
38217
38485
|
try {
|
|
38218
38486
|
await new Promise((resolvePromise, reject) => {
|
|
38219
|
-
const child =
|
|
38487
|
+
const child = spawn11("docker", dockerArgs, {
|
|
38220
38488
|
// When quiet, still show stderr so container errors surface
|
|
38221
38489
|
stdio: options.quiet ? ["pipe", "pipe", "inherit"] : "inherit"
|
|
38222
38490
|
});
|
|
@@ -38495,8 +38763,8 @@ var init_render2 = __esm({
|
|
|
38495
38763
|
const now = /* @__PURE__ */ new Date();
|
|
38496
38764
|
const datePart = now.toISOString().slice(0, 10);
|
|
38497
38765
|
const timePart = now.toTimeString().slice(0, 8).replace(/:/g, "-");
|
|
38498
|
-
const outputPath = args.output ? resolve28(args.output) :
|
|
38499
|
-
|
|
38766
|
+
const outputPath = args.output ? resolve28(args.output) : join44(rendersDir, `${project.name}_${datePart}_${timePart}${ext}`);
|
|
38767
|
+
mkdirSync24(dirname16(outputPath), { recursive: true });
|
|
38500
38768
|
const useDocker = args.docker ?? false;
|
|
38501
38769
|
const useGpu = args.gpu ?? false;
|
|
38502
38770
|
const quiet = args.quiet ?? false;
|
|
@@ -38971,8 +39239,8 @@ __export(layout_exports, {
|
|
|
38971
39239
|
examples: () => examples9
|
|
38972
39240
|
});
|
|
38973
39241
|
import { createServer } from "http";
|
|
38974
|
-
import { existsSync as
|
|
38975
|
-
import { dirname as dirname17, isAbsolute as isAbsolute6, join as
|
|
39242
|
+
import { existsSync as existsSync44, readFileSync as readFileSync30 } from "fs";
|
|
39243
|
+
import { dirname as dirname17, isAbsolute as isAbsolute6, join as join45, relative as relative5, resolve as resolve29 } from "path";
|
|
38976
39244
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
38977
39245
|
async function getCompositionDuration2(page) {
|
|
38978
39246
|
return page.evaluate(() => {
|
|
@@ -39042,8 +39310,8 @@ async function bundleProjectHtml(projectDir) {
|
|
|
39042
39310
|
"dist",
|
|
39043
39311
|
"hyperframe.runtime.iife.js"
|
|
39044
39312
|
);
|
|
39045
|
-
if (
|
|
39046
|
-
const runtimeSource =
|
|
39313
|
+
if (existsSync44(runtimePath)) {
|
|
39314
|
+
const runtimeSource = readFileSync30(runtimePath, "utf-8");
|
|
39047
39315
|
html = html.replace(
|
|
39048
39316
|
/<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
|
|
39049
39317
|
() => `<script data-hyperframes-preview-runtime="1">${runtimeSource}</script>`
|
|
@@ -39067,9 +39335,9 @@ async function serveProject(projectDir, html) {
|
|
|
39067
39335
|
res.end();
|
|
39068
39336
|
return;
|
|
39069
39337
|
}
|
|
39070
|
-
if (
|
|
39338
|
+
if (existsSync44(filePath)) {
|
|
39071
39339
|
res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
|
|
39072
|
-
res.end(
|
|
39340
|
+
res.end(readFileSync30(filePath));
|
|
39073
39341
|
return;
|
|
39074
39342
|
}
|
|
39075
39343
|
res.writeHead(404);
|
|
@@ -39171,11 +39439,11 @@ async function runLayoutAudit(projectDir, opts) {
|
|
|
39171
39439
|
}
|
|
39172
39440
|
function loadLayoutAuditScript() {
|
|
39173
39441
|
const candidates = [
|
|
39174
|
-
|
|
39175
|
-
|
|
39442
|
+
join45(__dirname2, "layout-audit.browser.js"),
|
|
39443
|
+
join45(__dirname2, "commands", "layout-audit.browser.js")
|
|
39176
39444
|
];
|
|
39177
39445
|
for (const candidate of candidates) {
|
|
39178
|
-
if (
|
|
39446
|
+
if (existsSync44(candidate)) return readFileSync30(candidate, "utf-8");
|
|
39179
39447
|
}
|
|
39180
39448
|
throw new Error("Missing layout audit browser script");
|
|
39181
39449
|
}
|
|
@@ -39395,12 +39663,12 @@ __export(info_exports, {
|
|
|
39395
39663
|
default: () => info_default,
|
|
39396
39664
|
examples: () => examples11
|
|
39397
39665
|
});
|
|
39398
|
-
import { readFileSync as
|
|
39399
|
-
import { join as
|
|
39666
|
+
import { readFileSync as readFileSync31, readdirSync as readdirSync17, statSync as statSync18 } from "fs";
|
|
39667
|
+
import { join as join46 } from "path";
|
|
39400
39668
|
function totalSize(dir) {
|
|
39401
39669
|
let total = 0;
|
|
39402
39670
|
for (const entry of readdirSync17(dir, { withFileTypes: true })) {
|
|
39403
|
-
const path2 =
|
|
39671
|
+
const path2 = join46(dir, entry.name);
|
|
39404
39672
|
if (entry.isDirectory()) {
|
|
39405
39673
|
total += totalSize(path2);
|
|
39406
39674
|
} else {
|
|
@@ -39432,7 +39700,7 @@ var init_info = __esm({
|
|
|
39432
39700
|
},
|
|
39433
39701
|
async run({ args }) {
|
|
39434
39702
|
const project = resolveProject(args.dir);
|
|
39435
|
-
const html =
|
|
39703
|
+
const html = readFileSync31(project.indexPath, "utf-8");
|
|
39436
39704
|
ensureDOMParser();
|
|
39437
39705
|
const parsed = parseHtml(html);
|
|
39438
39706
|
const tracks = new Set(parsed.elements.map((el) => el.zIndex));
|
|
@@ -39488,7 +39756,7 @@ __export(compositions_exports, {
|
|
|
39488
39756
|
default: () => compositions_default,
|
|
39489
39757
|
examples: () => examples12
|
|
39490
39758
|
});
|
|
39491
|
-
import { existsSync as
|
|
39759
|
+
import { existsSync as existsSync45, readFileSync as readFileSync32 } from "fs";
|
|
39492
39760
|
import { resolve as resolve30, dirname as dirname18 } from "path";
|
|
39493
39761
|
function parseCompositions(html, baseDir) {
|
|
39494
39762
|
const parser = new DOMParser();
|
|
@@ -39502,8 +39770,8 @@ function parseCompositions(html, baseDir) {
|
|
|
39502
39770
|
const compositionSrc = div.getAttribute("data-composition-src");
|
|
39503
39771
|
if (compositionSrc) {
|
|
39504
39772
|
const subPath = resolve30(baseDir, compositionSrc);
|
|
39505
|
-
if (
|
|
39506
|
-
const subHtml =
|
|
39773
|
+
if (existsSync45(subPath)) {
|
|
39774
|
+
const subHtml = readFileSync32(subPath, "utf-8");
|
|
39507
39775
|
const subInfo = parseSubComposition(subHtml, id, width, height);
|
|
39508
39776
|
compositions.push({ ...subInfo, source: compositionSrc });
|
|
39509
39777
|
return;
|
|
@@ -39597,7 +39865,7 @@ var init_compositions = __esm({
|
|
|
39597
39865
|
},
|
|
39598
39866
|
async run({ args }) {
|
|
39599
39867
|
const project = resolveProject(args.dir);
|
|
39600
|
-
const html =
|
|
39868
|
+
const html = readFileSync32(project.indexPath, "utf-8");
|
|
39601
39869
|
ensureDOMParser();
|
|
39602
39870
|
const compositions = parseCompositions(html, dirname18(project.indexPath));
|
|
39603
39871
|
if (compositions.length === 0) {
|
|
@@ -39635,8 +39903,8 @@ __export(benchmark_exports, {
|
|
|
39635
39903
|
default: () => benchmark_default,
|
|
39636
39904
|
examples: () => examples13
|
|
39637
39905
|
});
|
|
39638
|
-
import { existsSync as
|
|
39639
|
-
import { resolve as resolve31, join as
|
|
39906
|
+
import { existsSync as existsSync46, statSync as statSync19 } from "fs";
|
|
39907
|
+
import { resolve as resolve31, join as join47 } from "path";
|
|
39640
39908
|
var examples13, DEFAULT_CONFIGS, benchmark_default;
|
|
39641
39909
|
var init_benchmark = __esm({
|
|
39642
39910
|
"src/commands/benchmark.ts"() {
|
|
@@ -39711,7 +39979,7 @@ var init_benchmark = __esm({
|
|
|
39711
39979
|
s2?.start(`Benchmarking ${config.label}...`);
|
|
39712
39980
|
for (let i2 = 0; i2 < runsPerConfig; i2++) {
|
|
39713
39981
|
s2?.message(`${config.label} \u2014 run ${i2 + 1}/${runsPerConfig}`);
|
|
39714
|
-
const outputPath =
|
|
39982
|
+
const outputPath = join47(
|
|
39715
39983
|
benchDir,
|
|
39716
39984
|
`${config.label.replace(/[^a-zA-Z0-9]/g, "_")}_run${i2}.mp4`
|
|
39717
39985
|
);
|
|
@@ -39725,7 +39993,7 @@ var init_benchmark = __esm({
|
|
|
39725
39993
|
await producer.executeRenderJob(job, project.dir, outputPath);
|
|
39726
39994
|
const elapsedMs = Date.now() - startTime;
|
|
39727
39995
|
let fileSize = null;
|
|
39728
|
-
if (
|
|
39996
|
+
if (existsSync46(outputPath)) {
|
|
39729
39997
|
const stat3 = statSync19(outputPath);
|
|
39730
39998
|
fileSize = stat3.size;
|
|
39731
39999
|
}
|
|
@@ -39941,8 +40209,8 @@ __export(transcribe_exports2, {
|
|
|
39941
40209
|
default: () => transcribe_default,
|
|
39942
40210
|
examples: () => examples15
|
|
39943
40211
|
});
|
|
39944
|
-
import { existsSync as
|
|
39945
|
-
import { resolve as resolve32, join as
|
|
40212
|
+
import { existsSync as existsSync47, writeFileSync as writeFileSync19 } from "fs";
|
|
40213
|
+
import { resolve as resolve32, join as join48, extname as extname8 } from "path";
|
|
39946
40214
|
async function importTranscript(inputPath, dir, json) {
|
|
39947
40215
|
const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
|
|
39948
40216
|
const { words, format } = loadTranscript2(inputPath);
|
|
@@ -39950,8 +40218,8 @@ async function importTranscript(inputPath, dir, json) {
|
|
|
39950
40218
|
console.error(c.error("No words found in transcript."));
|
|
39951
40219
|
process.exit(1);
|
|
39952
40220
|
}
|
|
39953
|
-
const outPath =
|
|
39954
|
-
|
|
40221
|
+
const outPath = join48(dir, "transcript.json");
|
|
40222
|
+
writeFileSync19(outPath, JSON.stringify(words, null, 2));
|
|
39955
40223
|
patchCaptionHtml2(dir, words);
|
|
39956
40224
|
if (json) {
|
|
39957
40225
|
console.log(
|
|
@@ -39986,7 +40254,7 @@ async function transcribeAudio(inputPath, dir, opts) {
|
|
|
39986
40254
|
);
|
|
39987
40255
|
}
|
|
39988
40256
|
}
|
|
39989
|
-
|
|
40257
|
+
writeFileSync19(result.transcriptPath, JSON.stringify(words, null, 2));
|
|
39990
40258
|
patchCaptionHtml2(dir, words);
|
|
39991
40259
|
if (opts.json) {
|
|
39992
40260
|
console.log(
|
|
@@ -40067,7 +40335,7 @@ var init_transcribe2 = __esm({
|
|
|
40067
40335
|
},
|
|
40068
40336
|
async run({ args }) {
|
|
40069
40337
|
const inputPath = resolve32(args.input);
|
|
40070
|
-
if (!
|
|
40338
|
+
if (!existsSync47(inputPath)) {
|
|
40071
40339
|
console.error(c.error(`File not found: ${args.input}`));
|
|
40072
40340
|
process.exit(1);
|
|
40073
40341
|
}
|
|
@@ -40088,9 +40356,9 @@ var init_transcribe2 = __esm({
|
|
|
40088
40356
|
});
|
|
40089
40357
|
|
|
40090
40358
|
// src/tts/manager.ts
|
|
40091
|
-
import { existsSync as
|
|
40359
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync25 } from "fs";
|
|
40092
40360
|
import { homedir as homedir9 } from "os";
|
|
40093
|
-
import { join as
|
|
40361
|
+
import { join as join49 } from "path";
|
|
40094
40362
|
function inferLangFromVoiceId(voiceId) {
|
|
40095
40363
|
const first = voiceId.charAt(0).toLowerCase();
|
|
40096
40364
|
return VOICE_PREFIX_LANG[first] ?? "en-us";
|
|
@@ -40099,29 +40367,29 @@ function isSupportedLang(value) {
|
|
|
40099
40367
|
return SUPPORTED_LANGS.includes(value);
|
|
40100
40368
|
}
|
|
40101
40369
|
async function ensureModel2(model = DEFAULT_MODEL2, options) {
|
|
40102
|
-
const modelPath =
|
|
40103
|
-
if (
|
|
40370
|
+
const modelPath = join49(MODELS_DIR2, `${model}.onnx`);
|
|
40371
|
+
if (existsSync48(modelPath)) return modelPath;
|
|
40104
40372
|
const url = MODEL_URLS[model];
|
|
40105
40373
|
if (!url) {
|
|
40106
40374
|
throw new Error(
|
|
40107
40375
|
`Unknown TTS model: ${model}. Available: ${Object.keys(MODEL_URLS).join(", ")}`
|
|
40108
40376
|
);
|
|
40109
40377
|
}
|
|
40110
|
-
|
|
40378
|
+
mkdirSync25(MODELS_DIR2, { recursive: true });
|
|
40111
40379
|
options?.onProgress?.(`Downloading TTS model ${model} (~311 MB)...`);
|
|
40112
40380
|
await downloadFile(url, modelPath);
|
|
40113
|
-
if (!
|
|
40381
|
+
if (!existsSync48(modelPath)) {
|
|
40114
40382
|
throw new Error(`Model download failed: ${model}`);
|
|
40115
40383
|
}
|
|
40116
40384
|
return modelPath;
|
|
40117
40385
|
}
|
|
40118
40386
|
async function ensureVoices(options) {
|
|
40119
|
-
const voicesPath =
|
|
40120
|
-
if (
|
|
40121
|
-
|
|
40387
|
+
const voicesPath = join49(VOICES_DIR, "voices-v1.0.bin");
|
|
40388
|
+
if (existsSync48(voicesPath)) return voicesPath;
|
|
40389
|
+
mkdirSync25(VOICES_DIR, { recursive: true });
|
|
40122
40390
|
options?.onProgress?.("Downloading voice data (~27 MB)...");
|
|
40123
40391
|
await downloadFile(VOICES_URL, voicesPath);
|
|
40124
|
-
if (!
|
|
40392
|
+
if (!existsSync48(voicesPath)) {
|
|
40125
40393
|
throw new Error("Voice data download failed");
|
|
40126
40394
|
}
|
|
40127
40395
|
return voicesPath;
|
|
@@ -40131,9 +40399,9 @@ var init_manager3 = __esm({
|
|
|
40131
40399
|
"src/tts/manager.ts"() {
|
|
40132
40400
|
"use strict";
|
|
40133
40401
|
init_download();
|
|
40134
|
-
CACHE_DIR3 =
|
|
40135
|
-
MODELS_DIR2 =
|
|
40136
|
-
VOICES_DIR =
|
|
40402
|
+
CACHE_DIR3 = join49(homedir9(), ".cache", "hyperframes", "tts");
|
|
40403
|
+
MODELS_DIR2 = join49(CACHE_DIR3, "models");
|
|
40404
|
+
VOICES_DIR = join49(CACHE_DIR3, "voices");
|
|
40137
40405
|
DEFAULT_MODEL2 = "kokoro-v1.0";
|
|
40138
40406
|
MODEL_URLS = {
|
|
40139
40407
|
"kokoro-v1.0": "https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx"
|
|
@@ -40194,8 +40462,8 @@ __export(synthesize_exports, {
|
|
|
40194
40462
|
synthesize: () => synthesize
|
|
40195
40463
|
});
|
|
40196
40464
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
40197
|
-
import { existsSync as
|
|
40198
|
-
import { join as
|
|
40465
|
+
import { existsSync as existsSync49, writeFileSync as writeFileSync20, mkdirSync as mkdirSync26, readdirSync as readdirSync18, unlinkSync as unlinkSync6 } from "fs";
|
|
40466
|
+
import { join as join50, dirname as dirname19, basename as basename10 } from "path";
|
|
40199
40467
|
import { homedir as homedir10 } from "os";
|
|
40200
40468
|
function findPython() {
|
|
40201
40469
|
for (const name of ["python3", "python"]) {
|
|
@@ -40231,15 +40499,15 @@ function hasPythonPackage(python, pkg) {
|
|
|
40231
40499
|
}
|
|
40232
40500
|
}
|
|
40233
40501
|
function ensureSynthScript() {
|
|
40234
|
-
if (!
|
|
40235
|
-
|
|
40236
|
-
|
|
40502
|
+
if (!existsSync49(SCRIPT_PATH)) {
|
|
40503
|
+
mkdirSync26(SCRIPT_DIR, { recursive: true });
|
|
40504
|
+
writeFileSync20(SCRIPT_PATH, SYNTH_SCRIPT);
|
|
40237
40505
|
const currentName = basename10(SCRIPT_PATH);
|
|
40238
40506
|
try {
|
|
40239
40507
|
for (const entry of readdirSync18(SCRIPT_DIR)) {
|
|
40240
40508
|
if (entry !== currentName && /^synth(-v\d+)?\.py$/.test(entry)) {
|
|
40241
40509
|
try {
|
|
40242
|
-
unlinkSync6(
|
|
40510
|
+
unlinkSync6(join50(SCRIPT_DIR, entry));
|
|
40243
40511
|
} catch {
|
|
40244
40512
|
}
|
|
40245
40513
|
}
|
|
@@ -40273,7 +40541,7 @@ async function synthesize(text, outputPath, options) {
|
|
|
40273
40541
|
ensureVoices({ onProgress: options?.onProgress })
|
|
40274
40542
|
]);
|
|
40275
40543
|
const scriptPath = ensureSynthScript();
|
|
40276
|
-
|
|
40544
|
+
mkdirSync26(dirname19(outputPath), { recursive: true });
|
|
40277
40545
|
options?.onProgress?.(`Generating speech with voice ${voice} (${lang})...`);
|
|
40278
40546
|
try {
|
|
40279
40547
|
const stdout2 = execFileSync7(
|
|
@@ -40285,7 +40553,7 @@ async function synthesize(text, outputPath, options) {
|
|
|
40285
40553
|
stdio: ["pipe", "pipe", "pipe"]
|
|
40286
40554
|
}
|
|
40287
40555
|
);
|
|
40288
|
-
if (!
|
|
40556
|
+
if (!existsSync49(outputPath)) {
|
|
40289
40557
|
throw new Error("Synthesis completed but no output file was created");
|
|
40290
40558
|
}
|
|
40291
40559
|
const lines = stdout2.trim().split("\n");
|
|
@@ -40298,7 +40566,7 @@ async function synthesize(text, outputPath, options) {
|
|
|
40298
40566
|
langApplied: result.langApplied
|
|
40299
40567
|
};
|
|
40300
40568
|
} catch (err) {
|
|
40301
|
-
if (err instanceof SyntaxError &&
|
|
40569
|
+
if (err instanceof SyntaxError && existsSync49(outputPath)) {
|
|
40302
40570
|
throw new Error(
|
|
40303
40571
|
"Speech was generated but metadata could not be read. Check the output file manually."
|
|
40304
40572
|
);
|
|
@@ -40349,8 +40617,8 @@ print(json.dumps({
|
|
|
40349
40617
|
"langApplied": bool(lang and supports_lang),
|
|
40350
40618
|
}))
|
|
40351
40619
|
`;
|
|
40352
|
-
SCRIPT_DIR =
|
|
40353
|
-
SCRIPT_PATH =
|
|
40620
|
+
SCRIPT_DIR = join50(homedir10(), ".cache", "hyperframes", "tts");
|
|
40621
|
+
SCRIPT_PATH = join50(SCRIPT_DIR, "synth-v2.py");
|
|
40354
40622
|
}
|
|
40355
40623
|
});
|
|
40356
40624
|
|
|
@@ -40360,7 +40628,7 @@ __export(tts_exports, {
|
|
|
40360
40628
|
default: () => tts_default,
|
|
40361
40629
|
examples: () => examples16
|
|
40362
40630
|
});
|
|
40363
|
-
import { existsSync as
|
|
40631
|
+
import { existsSync as existsSync50, readFileSync as readFileSync33 } from "fs";
|
|
40364
40632
|
import { resolve as resolve33, extname as extname9 } from "path";
|
|
40365
40633
|
function listVoices(json) {
|
|
40366
40634
|
const rows = BUNDLED_VOICES.map((v) => ({ ...v, defaultLang: inferLangFromVoiceId(v.id) }));
|
|
@@ -40470,8 +40738,8 @@ var init_tts = __esm({
|
|
|
40470
40738
|
}
|
|
40471
40739
|
let text;
|
|
40472
40740
|
const maybeFile = resolve33(args.input);
|
|
40473
|
-
if (
|
|
40474
|
-
text =
|
|
40741
|
+
if (existsSync50(maybeFile) && extname9(maybeFile).toLowerCase() === ".txt") {
|
|
40742
|
+
text = readFileSync33(maybeFile, "utf-8").trim();
|
|
40475
40743
|
if (!text) {
|
|
40476
40744
|
console.error(c.error("File is empty."));
|
|
40477
40745
|
process.exit(1);
|
|
@@ -40563,15 +40831,15 @@ __export(docs_exports, {
|
|
|
40563
40831
|
default: () => docs_default,
|
|
40564
40832
|
examples: () => examples17
|
|
40565
40833
|
});
|
|
40566
|
-
import { readFileSync as
|
|
40567
|
-
import { resolve as resolve34, dirname as dirname20, join as
|
|
40834
|
+
import { readFileSync as readFileSync34, existsSync as existsSync51 } from "fs";
|
|
40835
|
+
import { resolve as resolve34, dirname as dirname20, join as join51 } from "path";
|
|
40568
40836
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
40569
40837
|
function docsDir() {
|
|
40570
40838
|
const thisFile = fileURLToPath7(import.meta.url);
|
|
40571
40839
|
const dir = dirname20(thisFile);
|
|
40572
40840
|
const devPath = resolve34(dir, "..", "docs");
|
|
40573
40841
|
const builtPath = resolve34(dir, "docs");
|
|
40574
|
-
return
|
|
40842
|
+
return existsSync51(devPath) ? devPath : builtPath;
|
|
40575
40843
|
}
|
|
40576
40844
|
function formatInlineCode(line) {
|
|
40577
40845
|
return line.replace(/`([^`]+)`/g, (_match, code) => c.accent(code));
|
|
@@ -40668,12 +40936,12 @@ var init_docs = __esm({
|
|
|
40668
40936
|
}
|
|
40669
40937
|
process.exit(1);
|
|
40670
40938
|
}
|
|
40671
|
-
const filePath =
|
|
40672
|
-
if (!
|
|
40939
|
+
const filePath = join51(docsDir(), entry.file);
|
|
40940
|
+
if (!existsSync51(filePath)) {
|
|
40673
40941
|
console.error(c.error(`Doc file not found: ${filePath}`));
|
|
40674
40942
|
process.exit(1);
|
|
40675
40943
|
}
|
|
40676
|
-
const content =
|
|
40944
|
+
const content = readFileSync34(filePath, "utf-8");
|
|
40677
40945
|
console.log();
|
|
40678
40946
|
renderMarkdown(content);
|
|
40679
40947
|
}
|
|
@@ -41099,8 +41367,8 @@ var validate_exports = {};
|
|
|
41099
41367
|
__export(validate_exports, {
|
|
41100
41368
|
default: () => validate_default
|
|
41101
41369
|
});
|
|
41102
|
-
import { existsSync as
|
|
41103
|
-
import { resolve as resolve35, join as
|
|
41370
|
+
import { existsSync as existsSync52, readFileSync as readFileSync35 } from "fs";
|
|
41371
|
+
import { resolve as resolve35, join as join52, dirname as dirname21 } from "path";
|
|
41104
41372
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
41105
41373
|
async function getCompositionDuration3(page) {
|
|
41106
41374
|
return page.evaluate(() => {
|
|
@@ -41155,8 +41423,8 @@ async function validateInBrowser(projectDir, opts) {
|
|
|
41155
41423
|
"dist",
|
|
41156
41424
|
"hyperframe.runtime.iife.js"
|
|
41157
41425
|
);
|
|
41158
|
-
if (
|
|
41159
|
-
const runtimeSource =
|
|
41426
|
+
if (existsSync52(runtimePath)) {
|
|
41427
|
+
const runtimeSource = readFileSync35(runtimePath, "utf-8");
|
|
41160
41428
|
html = html.replace(
|
|
41161
41429
|
/<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
|
|
41162
41430
|
() => `<script data-hyperframes-preview-runtime="1">${runtimeSource}</script>`
|
|
@@ -41171,10 +41439,10 @@ async function validateInBrowser(projectDir, opts) {
|
|
|
41171
41439
|
res.end(html);
|
|
41172
41440
|
return;
|
|
41173
41441
|
}
|
|
41174
|
-
const filePath =
|
|
41175
|
-
if (
|
|
41442
|
+
const filePath = join52(projectDir, decodeURIComponent(url));
|
|
41443
|
+
if (existsSync52(filePath)) {
|
|
41176
41444
|
res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
|
|
41177
|
-
res.end(
|
|
41445
|
+
res.end(readFileSync35(filePath));
|
|
41178
41446
|
return;
|
|
41179
41447
|
}
|
|
41180
41448
|
res.writeHead(404);
|
|
@@ -41364,14 +41632,14 @@ __export(snapshot_exports, {
|
|
|
41364
41632
|
default: () => snapshot_default,
|
|
41365
41633
|
examples: () => examples21
|
|
41366
41634
|
});
|
|
41367
|
-
import { spawn as
|
|
41368
|
-
import { existsSync as
|
|
41635
|
+
import { spawn as spawn12 } from "child_process";
|
|
41636
|
+
import { existsSync as existsSync53, mkdtempSync as mkdtempSync3, readFileSync as readFileSync36, mkdirSync as mkdirSync27, rmSync as rmSync10 } from "fs";
|
|
41369
41637
|
import { tmpdir as tmpdir5 } from "os";
|
|
41370
|
-
import { resolve as resolve36, join as
|
|
41638
|
+
import { resolve as resolve36, join as join53, dirname as dirname22, relative as relative6, isAbsolute as isAbsolute7 } from "path";
|
|
41371
41639
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
41372
41640
|
async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
|
|
41373
|
-
const tmp = mkdtempSync3(
|
|
41374
|
-
const outPath =
|
|
41641
|
+
const tmp = mkdtempSync3(join53(tmpdir5(), "hf-snapshot-frame-"));
|
|
41642
|
+
const outPath = join53(tmp, "frame.png");
|
|
41375
41643
|
try {
|
|
41376
41644
|
const result = await new Promise(
|
|
41377
41645
|
(resolvePromise) => {
|
|
@@ -41391,7 +41659,7 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
|
|
|
41391
41659
|
"-y",
|
|
41392
41660
|
outPath
|
|
41393
41661
|
);
|
|
41394
|
-
const ff =
|
|
41662
|
+
const ff = spawn12("ffmpeg", args);
|
|
41395
41663
|
let stderr = "";
|
|
41396
41664
|
let timedOut = false;
|
|
41397
41665
|
const timer = setTimeout(() => {
|
|
@@ -41411,8 +41679,8 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
|
|
|
41411
41679
|
});
|
|
41412
41680
|
}
|
|
41413
41681
|
);
|
|
41414
|
-
if (result.code !== 0 || result.timedOut || !
|
|
41415
|
-
return
|
|
41682
|
+
if (result.code !== 0 || result.timedOut || !existsSync53(outPath)) return null;
|
|
41683
|
+
return readFileSync36(outPath);
|
|
41416
41684
|
} finally {
|
|
41417
41685
|
try {
|
|
41418
41686
|
rmSync10(tmp, { recursive: true, force: true });
|
|
@@ -41434,8 +41702,8 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
41434
41702
|
"dist",
|
|
41435
41703
|
"hyperframe.runtime.iife.js"
|
|
41436
41704
|
);
|
|
41437
|
-
if (
|
|
41438
|
-
const runtimeSource =
|
|
41705
|
+
if (existsSync53(runtimePath)) {
|
|
41706
|
+
const runtimeSource = readFileSync36(runtimePath, "utf-8");
|
|
41439
41707
|
html = html.replace(
|
|
41440
41708
|
/<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
|
|
41441
41709
|
() => `<script data-hyperframes-preview-runtime="1">${runtimeSource}</script>`
|
|
@@ -41457,9 +41725,9 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
41457
41725
|
res.end();
|
|
41458
41726
|
return;
|
|
41459
41727
|
}
|
|
41460
|
-
if (
|
|
41728
|
+
if (existsSync53(filePath)) {
|
|
41461
41729
|
res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
|
|
41462
|
-
res.end(
|
|
41730
|
+
res.end(readFileSync36(filePath));
|
|
41463
41731
|
return;
|
|
41464
41732
|
}
|
|
41465
41733
|
res.writeHead(404);
|
|
@@ -41532,8 +41800,8 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
41532
41800
|
return [];
|
|
41533
41801
|
}
|
|
41534
41802
|
const positions = opts.at?.length ? opts.at : numFrames === 1 ? [duration / 2] : Array.from({ length: numFrames }, (_2, i2) => i2 / (numFrames - 1) * duration);
|
|
41535
|
-
const snapshotDir =
|
|
41536
|
-
|
|
41803
|
+
const snapshotDir = join53(projectDir, "snapshots");
|
|
41804
|
+
mkdirSync27(snapshotDir, { recursive: true });
|
|
41537
41805
|
let injectVideoFramesBatch2 = null;
|
|
41538
41806
|
let syncVideoFrameVisibility2 = null;
|
|
41539
41807
|
let extractMediaMetadata2 = null;
|
|
@@ -41607,7 +41875,7 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
41607
41875
|
const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
|
|
41608
41876
|
const candidate = resolve36(projectDir, decodedPath);
|
|
41609
41877
|
const rel = relative6(projectDir, candidate);
|
|
41610
|
-
if (!rel.startsWith("..") && !isAbsolute7(rel) &&
|
|
41878
|
+
if (!rel.startsWith("..") && !isAbsolute7(rel) && existsSync53(candidate)) {
|
|
41611
41879
|
filePath = candidate;
|
|
41612
41880
|
}
|
|
41613
41881
|
} catch {
|
|
@@ -41637,7 +41905,7 @@ async function captureSnapshots(projectDir, opts) {
|
|
|
41637
41905
|
}
|
|
41638
41906
|
const timeLabel = opts.at?.length ? `${time.toFixed(1)}s` : `${Math.round(time / duration * 100)}pct`;
|
|
41639
41907
|
const filename = `frame-${String(i2).padStart(2, "0")}-at-${timeLabel}.png`;
|
|
41640
|
-
const framePath =
|
|
41908
|
+
const framePath = join53(snapshotDir, filename);
|
|
41641
41909
|
await page.screenshot({ path: framePath, type: "png" });
|
|
41642
41910
|
savedPaths.push(`snapshots/${filename}`);
|
|
41643
41911
|
}
|
|
@@ -41722,14 +41990,14 @@ ${c.error("\u2717")} Snapshot failed: ${msg}`);
|
|
|
41722
41990
|
});
|
|
41723
41991
|
|
|
41724
41992
|
// src/capture/assetDownloader.ts
|
|
41725
|
-
import { writeFileSync as
|
|
41726
|
-
import { join as
|
|
41993
|
+
import { writeFileSync as writeFileSync21, mkdirSync as mkdirSync28 } from "fs";
|
|
41994
|
+
import { join as join54, extname as extname10 } from "path";
|
|
41727
41995
|
async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks) {
|
|
41728
|
-
const assetsDir =
|
|
41729
|
-
|
|
41996
|
+
const assetsDir = join54(outputDir, "assets");
|
|
41997
|
+
mkdirSync28(assetsDir, { recursive: true });
|
|
41730
41998
|
const assets = [];
|
|
41731
41999
|
const downloadedUrls = /* @__PURE__ */ new Set();
|
|
41732
|
-
|
|
42000
|
+
mkdirSync28(join54(outputDir, "assets", "svgs"), { recursive: true });
|
|
41733
42001
|
for (let i2 = 0; i2 < tokens.svgs.length && i2 < 30; i2++) {
|
|
41734
42002
|
const svg = tokens.svgs[i2];
|
|
41735
42003
|
if (!svg.outerHTML || svg.outerHTML.length < 50) continue;
|
|
@@ -41737,7 +42005,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
|
|
|
41737
42005
|
const name = label2 ? slugify(label2) + ".svg" : svg.isLogo ? `logo-${i2}.svg` : `icon-${i2}.svg`;
|
|
41738
42006
|
const localPath = `assets/svgs/${name}`;
|
|
41739
42007
|
try {
|
|
41740
|
-
|
|
42008
|
+
writeFileSync21(join54(outputDir, localPath), svg.outerHTML, "utf-8");
|
|
41741
42009
|
assets.push({ url: "", localPath, type: "svg" });
|
|
41742
42010
|
} catch {
|
|
41743
42011
|
}
|
|
@@ -41750,7 +42018,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
|
|
|
41750
42018
|
const localPath = `assets/${name}`;
|
|
41751
42019
|
const buffer = await fetchBuffer(icon.href);
|
|
41752
42020
|
if (buffer) {
|
|
41753
|
-
|
|
42021
|
+
writeFileSync21(join54(outputDir, localPath), buffer);
|
|
41754
42022
|
assets.push({ url: icon.href, localPath, type: "favicon" });
|
|
41755
42023
|
break;
|
|
41756
42024
|
}
|
|
@@ -41807,7 +42075,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
|
|
|
41807
42075
|
const slug = isMeaningful ? slugify(rawName) : `${prefix}-${imgIdx}`;
|
|
41808
42076
|
const name = `${slug}${ext}`;
|
|
41809
42077
|
const localPath = `assets/${name}`;
|
|
41810
|
-
|
|
42078
|
+
writeFileSync21(join54(outputDir, localPath), buffer);
|
|
41811
42079
|
assets.push({ url, localPath, type: "image" });
|
|
41812
42080
|
imgIdx++;
|
|
41813
42081
|
} catch {
|
|
@@ -41820,7 +42088,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
|
|
|
41820
42088
|
const localPath = `assets/og-image${ext}`;
|
|
41821
42089
|
const buffer = await fetchBuffer(tokens.ogImage);
|
|
41822
42090
|
if (buffer && buffer.length > 5e3) {
|
|
41823
|
-
|
|
42091
|
+
writeFileSync21(join54(outputDir, localPath), buffer);
|
|
41824
42092
|
assets.push({ url: tokens.ogImage, localPath, type: "image" });
|
|
41825
42093
|
}
|
|
41826
42094
|
} catch {
|
|
@@ -41843,8 +42111,8 @@ function normalizeUrl(u) {
|
|
|
41843
42111
|
}
|
|
41844
42112
|
}
|
|
41845
42113
|
async function downloadAndRewriteFonts(css, outputDir) {
|
|
41846
|
-
const assetsDir =
|
|
41847
|
-
|
|
42114
|
+
const assetsDir = join54(outputDir, "assets", "fonts");
|
|
42115
|
+
mkdirSync28(assetsDir, { recursive: true });
|
|
41848
42116
|
const fontUrlRegex = /url\(['"]?(https?:\/\/[^'")\s]+\.(?:woff2?|ttf|otf)[^'")\s]*?)['"]?\)/g;
|
|
41849
42117
|
const fontUrls = /* @__PURE__ */ new Set();
|
|
41850
42118
|
let match;
|
|
@@ -41879,11 +42147,11 @@ async function downloadAndRewriteFonts(css, outputDir) {
|
|
|
41879
42147
|
try {
|
|
41880
42148
|
const urlObj = new URL(fontUrl);
|
|
41881
42149
|
const filename = urlObj.pathname.split("/").pop() || `font-${count}.woff2`;
|
|
41882
|
-
const localPath =
|
|
42150
|
+
const localPath = join54(assetsDir, filename);
|
|
41883
42151
|
const relativePath = `assets/fonts/${filename}`;
|
|
41884
42152
|
const buffer = await fetchBuffer(fontUrl);
|
|
41885
42153
|
if (buffer) {
|
|
41886
|
-
|
|
42154
|
+
writeFileSync21(localPath, buffer);
|
|
41887
42155
|
rewritten = rewritten.split(fontUrl).join(relativePath);
|
|
41888
42156
|
familyCounts.set(family, familyCount + 1);
|
|
41889
42157
|
count++;
|
|
@@ -42676,8 +42944,8 @@ var init_animationCataloger = __esm({
|
|
|
42676
42944
|
});
|
|
42677
42945
|
|
|
42678
42946
|
// src/capture/mediaCapture.ts
|
|
42679
|
-
import { mkdirSync as
|
|
42680
|
-
import { join as
|
|
42947
|
+
import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync22, readdirSync as readdirSync19, readFileSync as readFileSync37, statSync as statSync20 } from "fs";
|
|
42948
|
+
import { join as join55 } from "path";
|
|
42681
42949
|
async function saveLottieAnimations(discoveredLotties, lottieDir) {
|
|
42682
42950
|
let savedCount = 0;
|
|
42683
42951
|
const savedHashes = /* @__PURE__ */ new Set();
|
|
@@ -42710,7 +42978,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
|
|
|
42710
42978
|
const hash2 = buf.toString("base64").slice(0, 100);
|
|
42711
42979
|
if (savedHashes.has(hash2)) continue;
|
|
42712
42980
|
savedHashes.add(hash2);
|
|
42713
|
-
|
|
42981
|
+
writeFileSync22(join55(lottieDir, `animation-${savedCount}.lottie`), buf);
|
|
42714
42982
|
savedCount++;
|
|
42715
42983
|
continue;
|
|
42716
42984
|
}
|
|
@@ -42728,7 +42996,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
|
|
|
42728
42996
|
} catch {
|
|
42729
42997
|
continue;
|
|
42730
42998
|
}
|
|
42731
|
-
|
|
42999
|
+
writeFileSync22(join55(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
|
|
42732
43000
|
savedCount++;
|
|
42733
43001
|
}
|
|
42734
43002
|
} catch {
|
|
@@ -42738,22 +43006,22 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
|
|
|
42738
43006
|
}
|
|
42739
43007
|
async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
|
|
42740
43008
|
const manifest = [];
|
|
42741
|
-
const previewDir =
|
|
42742
|
-
|
|
43009
|
+
const previewDir = join55(lottieDir, "previews");
|
|
43010
|
+
mkdirSync29(previewDir, { recursive: true });
|
|
42743
43011
|
for (const file of readdirSync19(lottieDir)) {
|
|
42744
43012
|
if (!file.endsWith(".json")) continue;
|
|
42745
43013
|
try {
|
|
42746
|
-
const raw = JSON.parse(
|
|
43014
|
+
const raw = JSON.parse(readFileSync37(join55(lottieDir, file), "utf-8"));
|
|
42747
43015
|
const fr = raw.fr || 30;
|
|
42748
43016
|
const dur = ((raw.op || 0) - (raw.ip || 0)) / fr;
|
|
42749
43017
|
const previewName = file.replace(".json", "-preview.png");
|
|
42750
|
-
const fileSize = statSync20(
|
|
43018
|
+
const fileSize = statSync20(join55(lottieDir, file)).size;
|
|
42751
43019
|
if (fileSize > 2e6) continue;
|
|
42752
43020
|
let previewPage;
|
|
42753
43021
|
try {
|
|
42754
43022
|
previewPage = await chromeBrowser.newPage();
|
|
42755
43023
|
await previewPage.setViewport({ width: 400, height: 400 });
|
|
42756
|
-
const animData = JSON.parse(
|
|
43024
|
+
const animData = JSON.parse(readFileSync37(join55(lottieDir, file), "utf-8"));
|
|
42757
43025
|
const midFrame = Math.floor(((raw.op || 0) - (raw.ip || 0)) * 0.3);
|
|
42758
43026
|
await previewPage.setContent(
|
|
42759
43027
|
`<!DOCTYPE html>
|
|
@@ -42783,7 +43051,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
|
|
|
42783
43051
|
await previewPage.waitForFunction(() => window.__READY === true, { timeout: 5e3 }).catch(() => {
|
|
42784
43052
|
});
|
|
42785
43053
|
await previewPage.screenshot({
|
|
42786
|
-
path:
|
|
43054
|
+
path: join55(previewDir, previewName),
|
|
42787
43055
|
type: "png",
|
|
42788
43056
|
omitBackground: true
|
|
42789
43057
|
});
|
|
@@ -42806,8 +43074,8 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
|
|
|
42806
43074
|
}
|
|
42807
43075
|
}
|
|
42808
43076
|
if (manifest.length > 0) {
|
|
42809
|
-
|
|
42810
|
-
|
|
43077
|
+
writeFileSync22(
|
|
43078
|
+
join55(outputDir, "extracted", "lottie-manifest.json"),
|
|
42811
43079
|
JSON.stringify(manifest, null, 2),
|
|
42812
43080
|
"utf-8"
|
|
42813
43081
|
);
|
|
@@ -42869,15 +43137,15 @@ async function captureVideoManifest(page, outputDir, progress) {
|
|
|
42869
43137
|
return true;
|
|
42870
43138
|
});
|
|
42871
43139
|
if (uniqueVideos.length > 0) {
|
|
42872
|
-
const videoManifestDir =
|
|
42873
|
-
|
|
42874
|
-
const previewDir =
|
|
42875
|
-
|
|
43140
|
+
const videoManifestDir = join55(outputDir, "assets", "videos");
|
|
43141
|
+
mkdirSync29(videoManifestDir, { recursive: true });
|
|
43142
|
+
const previewDir = join55(videoManifestDir, "previews");
|
|
43143
|
+
mkdirSync29(previewDir, { recursive: true });
|
|
42876
43144
|
const videoManifest = [];
|
|
42877
43145
|
for (let vi = 0; vi < uniqueVideos.length && vi < 20; vi++) {
|
|
42878
43146
|
const v = uniqueVideos[vi];
|
|
42879
43147
|
const previewName = `video-${vi}-preview.png`;
|
|
42880
|
-
const previewPath =
|
|
43148
|
+
const previewPath = join55(previewDir, previewName);
|
|
42881
43149
|
try {
|
|
42882
43150
|
await page.evaluate(`window.scrollTo(0, ${Math.max(0, v.top - 100)})`);
|
|
42883
43151
|
await new Promise((r2) => setTimeout(r2, 300));
|
|
@@ -42915,8 +43183,8 @@ async function captureVideoManifest(page, outputDir, progress) {
|
|
|
42915
43183
|
});
|
|
42916
43184
|
}
|
|
42917
43185
|
if (videoManifest.length > 0) {
|
|
42918
|
-
|
|
42919
|
-
|
|
43186
|
+
writeFileSync22(
|
|
43187
|
+
join55(outputDir, "extracted", "video-manifest.json"),
|
|
42920
43188
|
JSON.stringify(videoManifest, null, 2),
|
|
42921
43189
|
"utf-8"
|
|
42922
43190
|
);
|
|
@@ -65416,19 +65684,19 @@ function _moveValueRecursive(data, sourceKeys, destKeys, keyIdx, excludeKeys) {
|
|
|
65416
65684
|
const key2 = sourceKeys[keyIdx];
|
|
65417
65685
|
if (key2.endsWith("[]")) {
|
|
65418
65686
|
const keyName = key2.slice(0, -2);
|
|
65419
|
-
const
|
|
65420
|
-
if (keyName in
|
|
65421
|
-
for (const item of
|
|
65687
|
+
const dataRecord2 = data;
|
|
65688
|
+
if (keyName in dataRecord2 && Array.isArray(dataRecord2[keyName])) {
|
|
65689
|
+
for (const item of dataRecord2[keyName]) {
|
|
65422
65690
|
_moveValueRecursive(item, sourceKeys, destKeys, keyIdx + 1, excludeKeys);
|
|
65423
65691
|
}
|
|
65424
65692
|
}
|
|
65425
65693
|
} else if (key2 === "*") {
|
|
65426
65694
|
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
|
|
65427
|
-
const
|
|
65428
|
-
const keysToMove = Object.keys(
|
|
65695
|
+
const dataRecord2 = data;
|
|
65696
|
+
const keysToMove = Object.keys(dataRecord2).filter((k2) => !k2.startsWith("_") && !excludeKeys.has(k2));
|
|
65429
65697
|
const valuesToMove = {};
|
|
65430
65698
|
for (const k2 of keysToMove) {
|
|
65431
|
-
valuesToMove[k2] =
|
|
65699
|
+
valuesToMove[k2] = dataRecord2[k2];
|
|
65432
65700
|
}
|
|
65433
65701
|
for (const [k2, v] of Object.entries(valuesToMove)) {
|
|
65434
65702
|
const newDestKeys = [];
|
|
@@ -65439,16 +65707,16 @@ function _moveValueRecursive(data, sourceKeys, destKeys, keyIdx, excludeKeys) {
|
|
|
65439
65707
|
newDestKeys.push(dk);
|
|
65440
65708
|
}
|
|
65441
65709
|
}
|
|
65442
|
-
setValueByPath(
|
|
65710
|
+
setValueByPath(dataRecord2, newDestKeys, v);
|
|
65443
65711
|
}
|
|
65444
65712
|
for (const k2 of keysToMove) {
|
|
65445
|
-
delete
|
|
65713
|
+
delete dataRecord2[k2];
|
|
65446
65714
|
}
|
|
65447
65715
|
}
|
|
65448
65716
|
} else {
|
|
65449
|
-
const
|
|
65450
|
-
if (key2 in
|
|
65451
|
-
_moveValueRecursive(
|
|
65717
|
+
const dataRecord2 = data;
|
|
65718
|
+
if (key2 in dataRecord2) {
|
|
65719
|
+
_moveValueRecursive(dataRecord2[key2], sourceKeys, destKeys, keyIdx + 1, excludeKeys);
|
|
65452
65720
|
}
|
|
65453
65721
|
}
|
|
65454
65722
|
}
|
|
@@ -83371,8 +83639,8 @@ ${underline2}`);
|
|
|
83371
83639
|
});
|
|
83372
83640
|
|
|
83373
83641
|
// src/capture/contentExtractor.ts
|
|
83374
|
-
import { readdirSync as readdirSync20, statSync as statSync22, readFileSync as
|
|
83375
|
-
import { join as
|
|
83642
|
+
import { readdirSync as readdirSync20, statSync as statSync22, readFileSync as readFileSync38 } from "fs";
|
|
83643
|
+
import { join as join56 } from "path";
|
|
83376
83644
|
async function detectLibraries(page, capturedShaders) {
|
|
83377
83645
|
let detectedLibraries = [];
|
|
83378
83646
|
try {
|
|
@@ -83492,7 +83760,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
|
|
|
83492
83760
|
try {
|
|
83493
83761
|
const { GoogleGenAI: GoogleGenAI2 } = await Promise.resolve().then(() => (init_node4(), node_exports));
|
|
83494
83762
|
const ai = new GoogleGenAI2({ apiKey: geminiKey });
|
|
83495
|
-
const imageFiles = readdirSync20(
|
|
83763
|
+
const imageFiles = readdirSync20(join56(outputDir, "assets")).filter(
|
|
83496
83764
|
(f3) => /\.(png|jpg|jpeg|webp|gif)$/i.test(f3)
|
|
83497
83765
|
);
|
|
83498
83766
|
const model = process.env.HYPERFRAMES_GEMINI_MODEL || "gemini-3.1-flash-lite-preview";
|
|
@@ -83501,10 +83769,10 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
|
|
|
83501
83769
|
const batch = imageFiles.slice(i2, i2 + BATCH_SIZE);
|
|
83502
83770
|
const results = await Promise.allSettled(
|
|
83503
83771
|
batch.map(async (file) => {
|
|
83504
|
-
const filePath =
|
|
83772
|
+
const filePath = join56(outputDir, "assets", file);
|
|
83505
83773
|
const stat3 = statSync22(filePath);
|
|
83506
83774
|
if (stat3.size > 4e6) return { file, caption: "" };
|
|
83507
|
-
const buffer =
|
|
83775
|
+
const buffer = readFileSync38(filePath);
|
|
83508
83776
|
const base64 = buffer.toString("base64");
|
|
83509
83777
|
const ext = file.split(".").pop()?.toLowerCase() || "png";
|
|
83510
83778
|
const mimeType = ext === "jpg" ? "image/jpeg" : `image/${ext}`;
|
|
@@ -83550,11 +83818,11 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
|
|
|
83550
83818
|
const uncaptionedLines = [];
|
|
83551
83819
|
const svgLines = [];
|
|
83552
83820
|
const fontLines = [];
|
|
83553
|
-
const assetsPath =
|
|
83821
|
+
const assetsPath = join56(outputDir, "assets");
|
|
83554
83822
|
try {
|
|
83555
83823
|
for (const file of readdirSync20(assetsPath)) {
|
|
83556
83824
|
if (file === "svgs" || file === "fonts" || file === "lottie" || file === "videos") continue;
|
|
83557
|
-
const filePath =
|
|
83825
|
+
const filePath = join56(assetsPath, file);
|
|
83558
83826
|
const stat3 = statSync22(filePath);
|
|
83559
83827
|
if (!stat3.isFile()) continue;
|
|
83560
83828
|
const sizeKb = Math.round(stat3.size / 1024);
|
|
@@ -83583,7 +83851,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
|
|
|
83583
83851
|
} catch {
|
|
83584
83852
|
}
|
|
83585
83853
|
try {
|
|
83586
|
-
const svgsPath =
|
|
83854
|
+
const svgsPath = join56(assetsPath, "svgs");
|
|
83587
83855
|
for (const file of readdirSync20(svgsPath)) {
|
|
83588
83856
|
if (!file.endsWith(".svg")) continue;
|
|
83589
83857
|
const svgMatch = tokens.svgs.find(
|
|
@@ -83598,7 +83866,7 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
|
|
|
83598
83866
|
} catch {
|
|
83599
83867
|
}
|
|
83600
83868
|
try {
|
|
83601
|
-
const fontsPath =
|
|
83869
|
+
const fontsPath = join56(assetsPath, "fonts");
|
|
83602
83870
|
for (const file of readdirSync20(fontsPath)) {
|
|
83603
83871
|
fontLines.push(`fonts/${file} \u2014 font file`);
|
|
83604
83872
|
}
|
|
@@ -83617,13 +83885,13 @@ var agentPromptGenerator_exports = {};
|
|
|
83617
83885
|
__export(agentPromptGenerator_exports, {
|
|
83618
83886
|
generateAgentPrompt: () => generateAgentPrompt
|
|
83619
83887
|
});
|
|
83620
|
-
import { writeFileSync as
|
|
83621
|
-
import { join as
|
|
83888
|
+
import { writeFileSync as writeFileSync23 } from "fs";
|
|
83889
|
+
import { join as join57 } from "path";
|
|
83622
83890
|
function generateAgentPrompt(outputDir, url, tokens, _animations, hasScreenshot, hasLottie, hasShaders, _catalogedAssets, detectedLibraries) {
|
|
83623
83891
|
const prompt = buildPrompt(url, tokens, hasScreenshot, hasLottie, hasShaders, detectedLibraries);
|
|
83624
|
-
|
|
83625
|
-
|
|
83626
|
-
|
|
83892
|
+
writeFileSync23(join57(outputDir, "AGENTS.md"), prompt, "utf-8");
|
|
83893
|
+
writeFileSync23(join57(outputDir, "CLAUDE.md"), prompt, "utf-8");
|
|
83894
|
+
writeFileSync23(join57(outputDir, ".cursorrules"), prompt, "utf-8");
|
|
83627
83895
|
}
|
|
83628
83896
|
function buildPrompt(url, tokens, hasScreenshot, hasLottie, hasShaders, detectedLibraries) {
|
|
83629
83897
|
const title = tokens.title || new URL(url).hostname.replace(/^www\./, "");
|
|
@@ -83690,15 +83958,15 @@ var init_agentPromptGenerator = __esm({
|
|
|
83690
83958
|
});
|
|
83691
83959
|
|
|
83692
83960
|
// src/capture/scaffolding.ts
|
|
83693
|
-
import { existsSync as
|
|
83694
|
-
import { join as
|
|
83961
|
+
import { existsSync as existsSync54, writeFileSync as writeFileSync24, readFileSync as readFileSync39 } from "fs";
|
|
83962
|
+
import { join as join58, resolve as resolve37 } from "path";
|
|
83695
83963
|
function loadEnvFile(startDir) {
|
|
83696
83964
|
try {
|
|
83697
83965
|
let dir = resolve37(startDir);
|
|
83698
83966
|
for (let i2 = 0; i2 < 5; i2++) {
|
|
83699
83967
|
const envPath = resolve37(dir, ".env");
|
|
83700
83968
|
try {
|
|
83701
|
-
const envContent =
|
|
83969
|
+
const envContent = readFileSync39(envPath, "utf-8");
|
|
83702
83970
|
for (const line of envContent.split("\n")) {
|
|
83703
83971
|
const trimmed = line.trim();
|
|
83704
83972
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -83717,10 +83985,10 @@ function loadEnvFile(startDir) {
|
|
|
83717
83985
|
}
|
|
83718
83986
|
}
|
|
83719
83987
|
async function generateProjectScaffold(outputDir, url, tokens, animationCatalog, hasScreenshots, hasLotties, hasShaders, catalogedAssets, progress, warnings, detectedLibraries) {
|
|
83720
|
-
const metaPath =
|
|
83721
|
-
if (!
|
|
83988
|
+
const metaPath = join58(outputDir, "meta.json");
|
|
83989
|
+
if (!existsSync54(metaPath)) {
|
|
83722
83990
|
const hostname = new URL(url).hostname.replace(/^www\./, "");
|
|
83723
|
-
|
|
83991
|
+
writeFileSync24(
|
|
83724
83992
|
metaPath,
|
|
83725
83993
|
JSON.stringify({ id: hostname + "-video", name: tokens.title || hostname }, null, 2),
|
|
83726
83994
|
"utf-8"
|
|
@@ -83755,11 +84023,11 @@ var screenshotCapture_exports = {};
|
|
|
83755
84023
|
__export(screenshotCapture_exports, {
|
|
83756
84024
|
captureScrollScreenshots: () => captureScrollScreenshots
|
|
83757
84025
|
});
|
|
83758
|
-
import { writeFileSync as
|
|
83759
|
-
import { join as
|
|
84026
|
+
import { writeFileSync as writeFileSync25, mkdirSync as mkdirSync30 } from "fs";
|
|
84027
|
+
import { join as join59 } from "path";
|
|
83760
84028
|
async function captureScrollScreenshots(page, outputDir) {
|
|
83761
|
-
const screenshotsDir =
|
|
83762
|
-
|
|
84029
|
+
const screenshotsDir = join59(outputDir, "screenshots");
|
|
84030
|
+
mkdirSync30(screenshotsDir, { recursive: true });
|
|
83763
84031
|
const MAX_SCREENSHOTS = 20;
|
|
83764
84032
|
const filePaths = [];
|
|
83765
84033
|
try {
|
|
@@ -83792,9 +84060,9 @@ async function captureScrollScreenshots(page, outputDir) {
|
|
|
83792
84060
|
finalPositions[i2] / Math.max(1, scrollHeight - viewportHeight) * 100
|
|
83793
84061
|
);
|
|
83794
84062
|
const filename = `scroll-${String(Math.min(pct, 100)).padStart(3, "0")}.png`;
|
|
83795
|
-
const filePath =
|
|
84063
|
+
const filePath = join59(screenshotsDir, filename);
|
|
83796
84064
|
const buffer = await page.screenshot({ type: "png" });
|
|
83797
|
-
|
|
84065
|
+
writeFileSync25(filePath, buffer);
|
|
83798
84066
|
filePaths.push(`screenshots/${filename}`);
|
|
83799
84067
|
}
|
|
83800
84068
|
await page.evaluate(`window.scrollTo(0, 0)`);
|
|
@@ -84105,8 +84373,8 @@ var capture_exports = {};
|
|
|
84105
84373
|
__export(capture_exports, {
|
|
84106
84374
|
captureWebsite: () => captureWebsite
|
|
84107
84375
|
});
|
|
84108
|
-
import { mkdirSync as
|
|
84109
|
-
import { join as
|
|
84376
|
+
import { mkdirSync as mkdirSync31, writeFileSync as writeFileSync26, existsSync as existsSync55 } from "fs";
|
|
84377
|
+
import { join as join60 } from "path";
|
|
84110
84378
|
async function captureWebsite(opts, onProgress) {
|
|
84111
84379
|
const {
|
|
84112
84380
|
url,
|
|
@@ -84123,9 +84391,9 @@ async function captureWebsite(opts, onProgress) {
|
|
|
84123
84391
|
onProgress?.(stage, detail);
|
|
84124
84392
|
};
|
|
84125
84393
|
loadEnvFile(outputDir);
|
|
84126
|
-
|
|
84127
|
-
|
|
84128
|
-
|
|
84394
|
+
mkdirSync31(join60(outputDir, "extracted"), { recursive: true });
|
|
84395
|
+
mkdirSync31(join60(outputDir, "screenshots"), { recursive: true });
|
|
84396
|
+
mkdirSync31(join60(outputDir, "assets"), { recursive: true });
|
|
84129
84397
|
progress("browser", "Launching headless Chrome...");
|
|
84130
84398
|
const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
|
|
84131
84399
|
const browser = await ensureBrowser2();
|
|
@@ -84281,8 +84549,8 @@ async function captureWebsite(opts, onProgress) {
|
|
|
84281
84549
|
} catch {
|
|
84282
84550
|
}
|
|
84283
84551
|
if (discoveredLotties.length > 0) {
|
|
84284
|
-
const lottieDir =
|
|
84285
|
-
|
|
84552
|
+
const lottieDir = join60(outputDir, "assets", "lottie");
|
|
84553
|
+
mkdirSync31(lottieDir, { recursive: true });
|
|
84286
84554
|
const savedCount = await saveLottieAnimations(discoveredLotties, lottieDir);
|
|
84287
84555
|
if (savedCount > 0) {
|
|
84288
84556
|
await renderLottiePreviews(chromeBrowser, lottieDir, outputDir);
|
|
@@ -84300,8 +84568,8 @@ async function captureWebsite(opts, onProgress) {
|
|
|
84300
84568
|
return true;
|
|
84301
84569
|
});
|
|
84302
84570
|
capturedShaders = unique;
|
|
84303
|
-
|
|
84304
|
-
|
|
84571
|
+
writeFileSync26(
|
|
84572
|
+
join60(outputDir, "extracted", "shaders.json"),
|
|
84305
84573
|
JSON.stringify(unique, null, 2),
|
|
84306
84574
|
"utf-8"
|
|
84307
84575
|
);
|
|
@@ -84311,8 +84579,8 @@ async function captureWebsite(opts, onProgress) {
|
|
|
84311
84579
|
}
|
|
84312
84580
|
progress("tokens", "Extracting design tokens...");
|
|
84313
84581
|
const tokens = await extractTokens(page1);
|
|
84314
|
-
|
|
84315
|
-
|
|
84582
|
+
writeFileSync26(
|
|
84583
|
+
join60(outputDir, "extracted", "tokens.json"),
|
|
84316
84584
|
JSON.stringify(tokens, null, 2),
|
|
84317
84585
|
"utf-8"
|
|
84318
84586
|
);
|
|
@@ -84385,8 +84653,8 @@ async function captureWebsite(opts, onProgress) {
|
|
|
84385
84653
|
scrollTriggeredElements: (animationCatalog.scrollTargets || []).length,
|
|
84386
84654
|
representativeAnimations: representativeAnims
|
|
84387
84655
|
};
|
|
84388
|
-
|
|
84389
|
-
|
|
84656
|
+
writeFileSync26(
|
|
84657
|
+
join60(outputDir, "extracted", "animations.json"),
|
|
84390
84658
|
JSON.stringify(leanCatalog, null, 2),
|
|
84391
84659
|
"utf-8"
|
|
84392
84660
|
);
|
|
@@ -84397,18 +84665,18 @@ async function captureWebsite(opts, onProgress) {
|
|
|
84397
84665
|
assets = await downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks);
|
|
84398
84666
|
}
|
|
84399
84667
|
if (visibleTextContent) {
|
|
84400
|
-
|
|
84668
|
+
writeFileSync26(join60(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
|
|
84401
84669
|
}
|
|
84402
84670
|
if (catalogedAssets.length > 0) {
|
|
84403
|
-
|
|
84404
|
-
|
|
84671
|
+
writeFileSync26(
|
|
84672
|
+
join60(outputDir, "extracted", "assets-catalog.json"),
|
|
84405
84673
|
JSON.stringify(catalogedAssets, null, 2),
|
|
84406
84674
|
"utf-8"
|
|
84407
84675
|
);
|
|
84408
84676
|
}
|
|
84409
84677
|
if (detectedLibraries.length > 0) {
|
|
84410
|
-
|
|
84411
|
-
|
|
84678
|
+
writeFileSync26(
|
|
84679
|
+
join60(outputDir, "extracted", "detected-libraries.json"),
|
|
84412
84680
|
JSON.stringify(detectedLibraries, null, 2),
|
|
84413
84681
|
"utf-8"
|
|
84414
84682
|
);
|
|
@@ -84418,8 +84686,8 @@ async function captureWebsite(opts, onProgress) {
|
|
|
84418
84686
|
try {
|
|
84419
84687
|
const lines = generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCaptions);
|
|
84420
84688
|
if (lines.length > 0) {
|
|
84421
|
-
|
|
84422
|
-
|
|
84689
|
+
writeFileSync26(
|
|
84690
|
+
join60(outputDir, "extracted", "asset-descriptions.md"),
|
|
84423
84691
|
"# Asset Descriptions\n\nOne line per file. Read this instead of opening every image individually.\n\n" + lines.map((l) => "- " + l).join("\n") + "\n",
|
|
84424
84692
|
"utf-8"
|
|
84425
84693
|
);
|
|
@@ -84435,7 +84703,7 @@ async function captureWebsite(opts, onProgress) {
|
|
|
84435
84703
|
animationCatalog,
|
|
84436
84704
|
screenshots.length > 0,
|
|
84437
84705
|
discoveredLotties.length > 0,
|
|
84438
|
-
|
|
84706
|
+
existsSync55(join60(outputDir, "extracted", "shaders.json")),
|
|
84439
84707
|
catalogedAssets,
|
|
84440
84708
|
progress,
|
|
84441
84709
|
warnings,
|
|
@@ -84614,11 +84882,11 @@ var init_capture2 = __esm({
|
|
|
84614
84882
|
} catch (err) {
|
|
84615
84883
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
84616
84884
|
try {
|
|
84617
|
-
const { mkdirSync:
|
|
84618
|
-
|
|
84885
|
+
const { mkdirSync: mkdirSync33, writeFileSync: writeFileSync27 } = await import("fs");
|
|
84886
|
+
mkdirSync33(outputDir, { recursive: true });
|
|
84619
84887
|
const isTimeout = /timeout|timed out/i.test(errMsg);
|
|
84620
84888
|
const reason = isTimeout ? "Page navigation timed out \u2014 the site may be blocking headless browsers or requires authentication." : `Capture failed: ${errMsg}`;
|
|
84621
|
-
|
|
84889
|
+
writeFileSync27(
|
|
84622
84890
|
`${outputDir}/BLOCKED.md`,
|
|
84623
84891
|
`# Capture Failed
|
|
84624
84892
|
|
|
@@ -84781,10 +85049,10 @@ __export(autoUpdate_exports, {
|
|
|
84781
85049
|
reportCompletedUpdate: () => reportCompletedUpdate,
|
|
84782
85050
|
scheduleBackgroundInstall: () => scheduleBackgroundInstall
|
|
84783
85051
|
});
|
|
84784
|
-
import { spawn as
|
|
84785
|
-
import { appendFileSync as appendFileSync2, mkdirSync as
|
|
85052
|
+
import { spawn as spawn13 } from "child_process";
|
|
85053
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync32, openSync } from "fs";
|
|
84786
85054
|
import { homedir as homedir11 } from "os";
|
|
84787
|
-
import { join as
|
|
85055
|
+
import { join as join61 } from "path";
|
|
84788
85056
|
import { compareVersions as compareVersions2 } from "compare-versions";
|
|
84789
85057
|
function isAutoInstallDisabled() {
|
|
84790
85058
|
if (isDevMode()) return true;
|
|
@@ -84799,15 +85067,15 @@ function majorOf(version) {
|
|
|
84799
85067
|
}
|
|
84800
85068
|
function log(line) {
|
|
84801
85069
|
try {
|
|
84802
|
-
|
|
85070
|
+
mkdirSync32(CONFIG_DIR2, { recursive: true, mode: 448 });
|
|
84803
85071
|
appendFileSync2(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
|
|
84804
85072
|
`, { mode: 384 });
|
|
84805
85073
|
} catch {
|
|
84806
85074
|
}
|
|
84807
85075
|
}
|
|
84808
85076
|
function launchDetachedInstall(installCommand, version) {
|
|
84809
|
-
|
|
84810
|
-
const configFile =
|
|
85077
|
+
mkdirSync32(CONFIG_DIR2, { recursive: true, mode: 448 });
|
|
85078
|
+
const configFile = join61(CONFIG_DIR2, "config.json");
|
|
84811
85079
|
const nodeScript = `
|
|
84812
85080
|
const { exec } = require("node:child_process");
|
|
84813
85081
|
const { readFileSync, renameSync, writeFileSync } = require("node:fs");
|
|
@@ -84832,7 +85100,7 @@ function launchDetachedInstall(installCommand, version) {
|
|
|
84832
85100
|
});
|
|
84833
85101
|
`;
|
|
84834
85102
|
const out = openSync(LOG_FILE, "a", 384);
|
|
84835
|
-
const child =
|
|
85103
|
+
const child = spawn13(process.execPath, ["-e", nodeScript], {
|
|
84836
85104
|
detached: true,
|
|
84837
85105
|
stdio: ["ignore", out, out],
|
|
84838
85106
|
windowsHide: true,
|
|
@@ -84926,8 +85194,8 @@ var init_autoUpdate = __esm({
|
|
|
84926
85194
|
init_config();
|
|
84927
85195
|
init_env();
|
|
84928
85196
|
init_installerDetection();
|
|
84929
|
-
CONFIG_DIR2 =
|
|
84930
|
-
LOG_FILE =
|
|
85197
|
+
CONFIG_DIR2 = join61(homedir11(), ".hyperframes");
|
|
85198
|
+
LOG_FILE = join61(CONFIG_DIR2, "auto-update.log");
|
|
84931
85199
|
PENDING_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
84932
85200
|
}
|
|
84933
85201
|
});
|