@hyperframes/producer 0.4.22 → 0.5.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +5 -5
- package/dist/index.js +59 -16
- package/dist/index.js.map +3 -3
- package/dist/public-server.js +59 -16
- package/dist/public-server.js.map +3 -3
- package/dist/services/htmlCompiler.d.ts +1 -0
- package/dist/services/htmlCompiler.d.ts.map +1 -1
- package/dist/services/renderOrchestrator.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/public-server.js
CHANGED
|
@@ -101919,7 +101919,7 @@ function getAttr(tag, attr) {
|
|
|
101919
101919
|
return match2 ? match2[1] ?? null : null;
|
|
101920
101920
|
}
|
|
101921
101921
|
function hasAttr(tag, attr) {
|
|
101922
|
-
return new RegExp(
|
|
101922
|
+
return new RegExp(`\\s${attr}(?:\\s|=|>|/)`).test(tag);
|
|
101923
101923
|
}
|
|
101924
101924
|
function injectAttr(tag, attr, value) {
|
|
101925
101925
|
return tag.replace(/>$/, ` ${attr}="${value}">`);
|
|
@@ -102030,7 +102030,8 @@ function extractResolvedMedia(html) {
|
|
|
102030
102030
|
src: getAttr(tag, "src") ?? void 0,
|
|
102031
102031
|
start: startStr !== null ? parseFloat(startStr) : 0,
|
|
102032
102032
|
duration,
|
|
102033
|
-
mediaStart: mediaStartStr ? parseFloat(mediaStartStr) : 0
|
|
102033
|
+
mediaStart: mediaStartStr ? parseFloat(mediaStartStr) : 0,
|
|
102034
|
+
loop: hasAttr(tag, "loop")
|
|
102034
102035
|
});
|
|
102035
102036
|
}
|
|
102036
102037
|
return resolved;
|
|
@@ -104226,8 +104227,12 @@ async function initializeSession(session) {
|
|
|
104226
104227
|
}
|
|
104227
104228
|
});
|
|
104228
104229
|
page.on("pageerror", (err) => {
|
|
104229
|
-
const
|
|
104230
|
-
|
|
104230
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
104231
|
+
const text = `[Browser:PAGEERROR] ${message}`;
|
|
104232
|
+
const isPlayAbort = /^AbortError:/.test(message) && message.includes("play()") && message.includes("pause()");
|
|
104233
|
+
if (!isPlayAbort) {
|
|
104234
|
+
console.error(text);
|
|
104235
|
+
}
|
|
104231
104236
|
session.browserConsoleBuffer.push(text);
|
|
104232
104237
|
if (session.browserConsoleBuffer.length > BROWSER_CONSOLE_BUFFER_SIZE) {
|
|
104233
104238
|
session.browserConsoleBuffer.shift();
|
|
@@ -105498,6 +105503,7 @@ async function extractMediaMetadata(filePath) {
|
|
|
105498
105503
|
videoCodec: "png",
|
|
105499
105504
|
hasAudio: false,
|
|
105500
105505
|
isVFR: false,
|
|
105506
|
+
hasAlpha: false,
|
|
105501
105507
|
colorSpace: stillImageMeta.colorSpace
|
|
105502
105508
|
};
|
|
105503
105509
|
}
|
|
@@ -105512,6 +105518,9 @@ async function extractMediaMetadata(filePath) {
|
|
|
105512
105518
|
const colorSpaceVal = videoStream.color_space || "";
|
|
105513
105519
|
const ffprobeColorSpace = colorTransfer || colorPrimaries || colorSpaceVal ? { colorTransfer, colorPrimaries, colorSpace: colorSpaceVal } : null;
|
|
105514
105520
|
const colorSpace = ffprobeColorSpace ?? stillImageMeta?.colorSpace ?? null;
|
|
105521
|
+
const pixelFormat = videoStream.pix_fmt || "";
|
|
105522
|
+
const alphaMode = videoStream.tags?.alpha_mode || "";
|
|
105523
|
+
const hasAlpha = /(^|[^a-z])yuva|rgba|argb|bgra|gbrap|gray[a-z0-9]*a/i.test(pixelFormat) || alphaMode === "1";
|
|
105515
105524
|
return {
|
|
105516
105525
|
durationSeconds: output2?.format.duration ? parseFloat(output2.format.duration) : 0,
|
|
105517
105526
|
width: videoStream.width || stillImageMeta?.width || 0,
|
|
@@ -105520,6 +105529,7 @@ async function extractMediaMetadata(filePath) {
|
|
|
105520
105529
|
videoCodec: videoStream.codec_name || "unknown",
|
|
105521
105530
|
hasAudio: output2?.streams.some((s) => s.codec_type === "audio") ?? false,
|
|
105522
105531
|
isVFR,
|
|
105532
|
+
hasAlpha,
|
|
105523
105533
|
colorSpace
|
|
105524
105534
|
};
|
|
105525
105535
|
})();
|
|
@@ -105820,6 +105830,7 @@ function parseVideoElements(html) {
|
|
|
105820
105830
|
start,
|
|
105821
105831
|
end,
|
|
105822
105832
|
mediaStart: mediaStartAttr ? parseFloat(mediaStartAttr) : 0,
|
|
105833
|
+
loop: el.hasAttribute("loop"),
|
|
105823
105834
|
hasAudio: hasAudioAttr === "true"
|
|
105824
105835
|
});
|
|
105825
105836
|
}
|
|
@@ -105855,10 +105866,11 @@ function parseImageElements(html) {
|
|
|
105855
105866
|
}
|
|
105856
105867
|
async function extractVideoFramesRange(videoPath, videoId, startTime, duration, options, signal, config2, outputDirOverride) {
|
|
105857
105868
|
const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
105858
|
-
const { fps, outputDir, quality = 95
|
|
105869
|
+
const { fps, outputDir, quality = 95 } = options;
|
|
105859
105870
|
const videoOutputDir = outputDirOverride ?? join9(outputDir, videoId);
|
|
105860
105871
|
if (!existsSync9(videoOutputDir)) mkdirSync6(videoOutputDir, { recursive: true });
|
|
105861
105872
|
const metadata = await extractMediaMetadata(videoPath);
|
|
105873
|
+
const format3 = resolveFrameFormat(metadata, options.format);
|
|
105862
105874
|
const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${format3}`;
|
|
105863
105875
|
const outputPattern = join9(videoOutputDir, framePattern);
|
|
105864
105876
|
const isHdr = isHdrColorSpace(metadata.colorSpace);
|
|
@@ -105867,6 +105879,9 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
|
|
|
105867
105879
|
if (isHdr && isMacOS) {
|
|
105868
105880
|
args.push("-hwaccel", "videotoolbox");
|
|
105869
105881
|
}
|
|
105882
|
+
if (metadata.hasAlpha && metadata.videoCodec === "vp9") {
|
|
105883
|
+
args.push("-c:v", "libvpx-vp9");
|
|
105884
|
+
}
|
|
105870
105885
|
args.push("-ss", String(startTime), "-i", videoPath, "-t", String(duration));
|
|
105871
105886
|
const vfFilters = [];
|
|
105872
105887
|
if (isHdr && isMacOS) {
|
|
@@ -105978,6 +105993,10 @@ function resolveSegmentDuration(requested, mediaStart, metadata) {
|
|
|
105978
105993
|
const sourceRemaining = metadata.durationSeconds - mediaStart;
|
|
105979
105994
|
return sourceRemaining > 0 ? sourceRemaining : metadata.durationSeconds;
|
|
105980
105995
|
}
|
|
105996
|
+
function resolveFrameFormat(metadata, requested) {
|
|
105997
|
+
if (requested) return requested;
|
|
105998
|
+
return metadata.hasAlpha ? "png" : "jpg";
|
|
105999
|
+
}
|
|
105981
106000
|
async function convertVfrToCfr(inputPath, outputPath, targetFps, startTime, duration, signal, config2) {
|
|
105982
106001
|
const timeout2 = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
105983
106002
|
const args = [
|
|
@@ -106170,12 +106189,12 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
106170
106189
|
breakdown.vfrPreflightMs = Date.now() - vfrPreflightStart;
|
|
106171
106190
|
const phase3Start = Date.now();
|
|
106172
106191
|
const cacheRootDir = config2?.extractCacheDir;
|
|
106173
|
-
const cacheFormat = options.format ?? "jpg";
|
|
106174
106192
|
async function tryCachedExtract(video, videoPath, videoDuration, i) {
|
|
106175
106193
|
if (!cacheRootDir) return null;
|
|
106176
106194
|
const keyInput = cacheKeyInputs[i];
|
|
106177
106195
|
const probedMeta = videoMetadata[i];
|
|
106178
106196
|
if (!keyInput || !probedMeta) return null;
|
|
106197
|
+
const cacheFormat = resolveFrameFormat(probedMeta, options.format);
|
|
106179
106198
|
const keyDuration = resolveSegmentDuration(
|
|
106180
106199
|
keyInput.end - keyInput.start,
|
|
106181
106200
|
keyInput.mediaStart,
|
|
@@ -106208,7 +106227,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
106208
106227
|
video.id,
|
|
106209
106228
|
video.mediaStart,
|
|
106210
106229
|
videoDuration,
|
|
106211
|
-
options,
|
|
106230
|
+
{ ...options, format: cacheFormat },
|
|
106212
106231
|
signal,
|
|
106213
106232
|
config2,
|
|
106214
106233
|
lookup.entry.dir
|
|
@@ -106238,7 +106257,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
106238
106257
|
video.id,
|
|
106239
106258
|
video.mediaStart,
|
|
106240
106259
|
videoDuration,
|
|
106241
|
-
options,
|
|
106260
|
+
{ ...options, format: resolveFrameFormat(probedMeta, options.format) },
|
|
106242
106261
|
signal,
|
|
106243
106262
|
config2
|
|
106244
106263
|
);
|
|
@@ -106271,10 +106290,17 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
106271
106290
|
phaseBreakdown: breakdown
|
|
106272
106291
|
};
|
|
106273
106292
|
}
|
|
106274
|
-
function getFrameAtTime(extracted, globalTime, videoStart) {
|
|
106275
|
-
|
|
106293
|
+
function getFrameAtTime(extracted, globalTime, videoStart, loop = false, mediaStart = 0) {
|
|
106294
|
+
let localTime = globalTime - videoStart;
|
|
106276
106295
|
if (localTime < 0) return null;
|
|
106296
|
+
const loopDuration = Math.max(0, extracted.metadata.durationSeconds - mediaStart);
|
|
106297
|
+
if (loop && loopDuration > 0 && localTime >= loopDuration) {
|
|
106298
|
+
localTime %= loopDuration;
|
|
106299
|
+
}
|
|
106277
106300
|
const frameIndex = Math.floor(localTime * extracted.fps);
|
|
106301
|
+
if (loop && frameIndex >= extracted.totalFrames && extracted.totalFrames > 0) {
|
|
106302
|
+
return extracted.framePaths.get(extracted.totalFrames - 1) || null;
|
|
106303
|
+
}
|
|
106278
106304
|
if (frameIndex < 0 || frameIndex >= extracted.totalFrames) return null;
|
|
106279
106305
|
return extracted.framePaths.get(frameIndex) || null;
|
|
106280
106306
|
}
|
|
@@ -106284,8 +106310,8 @@ var FrameLookupTable = class {
|
|
|
106284
106310
|
activeVideoIds = /* @__PURE__ */ new Set();
|
|
106285
106311
|
startCursor = 0;
|
|
106286
106312
|
lastTime = null;
|
|
106287
|
-
addVideo(extracted, start, end, mediaStart) {
|
|
106288
|
-
this.videos.set(extracted.videoId, { extracted, start, end, mediaStart });
|
|
106313
|
+
addVideo(extracted, start, end, mediaStart, loop = false) {
|
|
106314
|
+
this.videos.set(extracted.videoId, { extracted, start, end, mediaStart, loop });
|
|
106289
106315
|
this.orderedVideos = Array.from(this.videos.entries()).map(([videoId, video]) => ({ videoId, ...video })).sort((a, b) => a.start - b.start);
|
|
106290
106316
|
this.resetActiveState();
|
|
106291
106317
|
}
|
|
@@ -106293,7 +106319,7 @@ var FrameLookupTable = class {
|
|
|
106293
106319
|
const video = this.videos.get(videoId);
|
|
106294
106320
|
if (!video) return null;
|
|
106295
106321
|
if (globalTime < video.start || globalTime >= video.end) return null;
|
|
106296
|
-
return getFrameAtTime(video.extracted, globalTime, video.start);
|
|
106322
|
+
return getFrameAtTime(video.extracted, globalTime, video.start, video.loop, video.mediaStart);
|
|
106297
106323
|
}
|
|
106298
106324
|
resetActiveState() {
|
|
106299
106325
|
this.activeVideoIds.clear();
|
|
@@ -106342,8 +106368,19 @@ var FrameLookupTable = class {
|
|
|
106342
106368
|
for (const videoId of this.activeVideoIds) {
|
|
106343
106369
|
const video = this.videos.get(videoId);
|
|
106344
106370
|
if (!video) continue;
|
|
106345
|
-
|
|
106371
|
+
let localTime = globalTime - video.start;
|
|
106372
|
+
const loopDuration = Math.max(0, video.extracted.metadata.durationSeconds - video.mediaStart);
|
|
106373
|
+
if (video.loop && loopDuration > 0 && localTime >= loopDuration) {
|
|
106374
|
+
localTime %= loopDuration;
|
|
106375
|
+
}
|
|
106346
106376
|
const frameIndex = Math.floor(localTime * video.extracted.fps);
|
|
106377
|
+
if (video.loop && frameIndex >= video.extracted.totalFrames) {
|
|
106378
|
+
const framePath2 = video.extracted.framePaths.get(video.extracted.totalFrames - 1);
|
|
106379
|
+
if (framePath2) {
|
|
106380
|
+
frames.set(videoId, { framePath: framePath2, frameIndex: video.extracted.totalFrames - 1 });
|
|
106381
|
+
}
|
|
106382
|
+
continue;
|
|
106383
|
+
}
|
|
106347
106384
|
if (frameIndex < 0 || frameIndex >= video.extracted.totalFrames) continue;
|
|
106348
106385
|
const framePath = video.extracted.framePaths.get(frameIndex);
|
|
106349
106386
|
if (!framePath) continue;
|
|
@@ -106377,7 +106414,7 @@ function createFrameLookupTable(videos, extracted) {
|
|
|
106377
106414
|
for (const ext of extracted) extractedMap.set(ext.videoId, ext);
|
|
106378
106415
|
for (const video of videos) {
|
|
106379
106416
|
const ext = extractedMap.get(video.id);
|
|
106380
|
-
if (ext) table.addVideo(ext, video.start, video.end, video.mediaStart);
|
|
106417
|
+
if (ext) table.addVideo(ext, video.start, video.end, video.mediaStart, video.loop);
|
|
106381
106418
|
}
|
|
106382
106419
|
return table;
|
|
106383
106420
|
}
|
|
@@ -109300,7 +109337,7 @@ async function compileHtmlFile(html, baseDir, downloadDir) {
|
|
|
109300
109337
|
let compiledHtml = resolutions.length > 0 ? injectDurations(staticCompiled, resolutions) : staticCompiled;
|
|
109301
109338
|
const preResolved = extractResolvedMedia(compiledHtml);
|
|
109302
109339
|
const clampResults = await Promise.all(
|
|
109303
|
-
preResolved.filter((el) => !!el.src).map(async (el) => {
|
|
109340
|
+
preResolved.filter((el) => !!el.src && !el.loop).map(async (el) => {
|
|
109304
109341
|
const { duration: maxDuration } = await resolveMediaDuration(
|
|
109305
109342
|
el.src,
|
|
109306
109343
|
el.mediaStart,
|
|
@@ -109908,6 +109945,7 @@ async function discoverMediaFromBrowser(page) {
|
|
|
109908
109945
|
const end = parseFloat(htmlEl.getAttribute("data-end") || "0");
|
|
109909
109946
|
const duration = parseFloat(htmlEl.getAttribute("data-duration") || "0");
|
|
109910
109947
|
const mediaStart = parseFloat(htmlEl.getAttribute("data-media-start") || "0");
|
|
109948
|
+
const loop = htmlEl.hasAttribute("loop");
|
|
109911
109949
|
const hasAudio = htmlEl.getAttribute("data-has-audio") === "true";
|
|
109912
109950
|
const volume = parseFloat(htmlEl.getAttribute("data-volume") || "1");
|
|
109913
109951
|
results.push({
|
|
@@ -109918,6 +109956,7 @@ async function discoverMediaFromBrowser(page) {
|
|
|
109918
109956
|
end,
|
|
109919
109957
|
duration,
|
|
109920
109958
|
mediaStart,
|
|
109959
|
+
loop,
|
|
109921
109960
|
hasAudio,
|
|
109922
109961
|
volume
|
|
109923
109962
|
});
|
|
@@ -110792,6 +110831,9 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110792
110831
|
if (el.hasAudio && !existing.hasAudio) {
|
|
110793
110832
|
existing.hasAudio = true;
|
|
110794
110833
|
}
|
|
110834
|
+
if (el.loop && !existing.loop) {
|
|
110835
|
+
existing.loop = true;
|
|
110836
|
+
}
|
|
110795
110837
|
}
|
|
110796
110838
|
} else {
|
|
110797
110839
|
composition.videos.push({
|
|
@@ -110800,6 +110842,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110800
110842
|
start: el.start,
|
|
110801
110843
|
end: el.end,
|
|
110802
110844
|
mediaStart: el.mediaStart,
|
|
110845
|
+
loop: el.loop,
|
|
110803
110846
|
hasAudio: el.hasAudio
|
|
110804
110847
|
});
|
|
110805
110848
|
existingVideoIds.add(el.id);
|