@hyperframes/producer 0.4.22 → 0.4.23
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 +53 -14
- package/dist/index.js.map +3 -3
- package/dist/public-server.js +53 -14
- 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/index.js
CHANGED
|
@@ -99130,7 +99130,7 @@ function getAttr(tag, attr) {
|
|
|
99130
99130
|
return match2 ? match2[1] ?? null : null;
|
|
99131
99131
|
}
|
|
99132
99132
|
function hasAttr(tag, attr) {
|
|
99133
|
-
return new RegExp(
|
|
99133
|
+
return new RegExp(`\\s${attr}(?:\\s|=|>|/)`).test(tag);
|
|
99134
99134
|
}
|
|
99135
99135
|
function injectAttr(tag, attr, value) {
|
|
99136
99136
|
return tag.replace(/>$/, ` ${attr}="${value}">`);
|
|
@@ -99241,7 +99241,8 @@ function extractResolvedMedia(html) {
|
|
|
99241
99241
|
src: getAttr(tag, "src") ?? void 0,
|
|
99242
99242
|
start: startStr !== null ? parseFloat(startStr) : 0,
|
|
99243
99243
|
duration,
|
|
99244
|
-
mediaStart: mediaStartStr ? parseFloat(mediaStartStr) : 0
|
|
99244
|
+
mediaStart: mediaStartStr ? parseFloat(mediaStartStr) : 0,
|
|
99245
|
+
loop: hasAttr(tag, "loop")
|
|
99245
99246
|
});
|
|
99246
99247
|
}
|
|
99247
99248
|
return resolved;
|
|
@@ -102709,6 +102710,7 @@ async function extractMediaMetadata(filePath) {
|
|
|
102709
102710
|
videoCodec: "png",
|
|
102710
102711
|
hasAudio: false,
|
|
102711
102712
|
isVFR: false,
|
|
102713
|
+
hasAlpha: false,
|
|
102712
102714
|
colorSpace: stillImageMeta.colorSpace
|
|
102713
102715
|
};
|
|
102714
102716
|
}
|
|
@@ -102723,6 +102725,9 @@ async function extractMediaMetadata(filePath) {
|
|
|
102723
102725
|
const colorSpaceVal = videoStream.color_space || "";
|
|
102724
102726
|
const ffprobeColorSpace = colorTransfer || colorPrimaries || colorSpaceVal ? { colorTransfer, colorPrimaries, colorSpace: colorSpaceVal } : null;
|
|
102725
102727
|
const colorSpace = ffprobeColorSpace ?? stillImageMeta?.colorSpace ?? null;
|
|
102728
|
+
const pixelFormat = videoStream.pix_fmt || "";
|
|
102729
|
+
const alphaMode = videoStream.tags?.alpha_mode || "";
|
|
102730
|
+
const hasAlpha = /(^|[^a-z])yuva|rgba|argb|bgra|gbrap|gray[a-z0-9]*a/i.test(pixelFormat) || alphaMode === "1";
|
|
102726
102731
|
return {
|
|
102727
102732
|
durationSeconds: output2?.format.duration ? parseFloat(output2.format.duration) : 0,
|
|
102728
102733
|
width: videoStream.width || stillImageMeta?.width || 0,
|
|
@@ -102731,6 +102736,7 @@ async function extractMediaMetadata(filePath) {
|
|
|
102731
102736
|
videoCodec: videoStream.codec_name || "unknown",
|
|
102732
102737
|
hasAudio: output2?.streams.some((s) => s.codec_type === "audio") ?? false,
|
|
102733
102738
|
isVFR,
|
|
102739
|
+
hasAlpha,
|
|
102734
102740
|
colorSpace
|
|
102735
102741
|
};
|
|
102736
102742
|
})();
|
|
@@ -103031,6 +103037,7 @@ function parseVideoElements(html) {
|
|
|
103031
103037
|
start,
|
|
103032
103038
|
end,
|
|
103033
103039
|
mediaStart: mediaStartAttr ? parseFloat(mediaStartAttr) : 0,
|
|
103040
|
+
loop: el.hasAttribute("loop"),
|
|
103034
103041
|
hasAudio: hasAudioAttr === "true"
|
|
103035
103042
|
});
|
|
103036
103043
|
}
|
|
@@ -103066,10 +103073,11 @@ function parseImageElements(html) {
|
|
|
103066
103073
|
}
|
|
103067
103074
|
async function extractVideoFramesRange(videoPath, videoId, startTime, duration, options, signal, config2, outputDirOverride) {
|
|
103068
103075
|
const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
103069
|
-
const { fps, outputDir, quality = 95
|
|
103076
|
+
const { fps, outputDir, quality = 95 } = options;
|
|
103070
103077
|
const videoOutputDir = outputDirOverride ?? join9(outputDir, videoId);
|
|
103071
103078
|
if (!existsSync9(videoOutputDir)) mkdirSync6(videoOutputDir, { recursive: true });
|
|
103072
103079
|
const metadata = await extractMediaMetadata(videoPath);
|
|
103080
|
+
const format3 = resolveFrameFormat(metadata, options.format);
|
|
103073
103081
|
const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${format3}`;
|
|
103074
103082
|
const outputPattern = join9(videoOutputDir, framePattern);
|
|
103075
103083
|
const isHdr = isHdrColorSpace(metadata.colorSpace);
|
|
@@ -103078,6 +103086,9 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
|
|
|
103078
103086
|
if (isHdr && isMacOS) {
|
|
103079
103087
|
args.push("-hwaccel", "videotoolbox");
|
|
103080
103088
|
}
|
|
103089
|
+
if (metadata.hasAlpha && metadata.videoCodec === "vp9") {
|
|
103090
|
+
args.push("-c:v", "libvpx-vp9");
|
|
103091
|
+
}
|
|
103081
103092
|
args.push("-ss", String(startTime), "-i", videoPath, "-t", String(duration));
|
|
103082
103093
|
const vfFilters = [];
|
|
103083
103094
|
if (isHdr && isMacOS) {
|
|
@@ -103189,6 +103200,10 @@ function resolveSegmentDuration(requested, mediaStart, metadata) {
|
|
|
103189
103200
|
const sourceRemaining = metadata.durationSeconds - mediaStart;
|
|
103190
103201
|
return sourceRemaining > 0 ? sourceRemaining : metadata.durationSeconds;
|
|
103191
103202
|
}
|
|
103203
|
+
function resolveFrameFormat(metadata, requested) {
|
|
103204
|
+
if (requested) return requested;
|
|
103205
|
+
return metadata.hasAlpha ? "png" : "jpg";
|
|
103206
|
+
}
|
|
103192
103207
|
async function convertVfrToCfr(inputPath, outputPath, targetFps, startTime, duration, signal, config2) {
|
|
103193
103208
|
const timeout2 = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
103194
103209
|
const args = [
|
|
@@ -103381,12 +103396,12 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
103381
103396
|
breakdown.vfrPreflightMs = Date.now() - vfrPreflightStart;
|
|
103382
103397
|
const phase3Start = Date.now();
|
|
103383
103398
|
const cacheRootDir = config2?.extractCacheDir;
|
|
103384
|
-
const cacheFormat = options.format ?? "jpg";
|
|
103385
103399
|
async function tryCachedExtract(video, videoPath, videoDuration, i) {
|
|
103386
103400
|
if (!cacheRootDir) return null;
|
|
103387
103401
|
const keyInput = cacheKeyInputs[i];
|
|
103388
103402
|
const probedMeta = videoMetadata[i];
|
|
103389
103403
|
if (!keyInput || !probedMeta) return null;
|
|
103404
|
+
const cacheFormat = resolveFrameFormat(probedMeta, options.format);
|
|
103390
103405
|
const keyDuration = resolveSegmentDuration(
|
|
103391
103406
|
keyInput.end - keyInput.start,
|
|
103392
103407
|
keyInput.mediaStart,
|
|
@@ -103419,7 +103434,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
103419
103434
|
video.id,
|
|
103420
103435
|
video.mediaStart,
|
|
103421
103436
|
videoDuration,
|
|
103422
|
-
options,
|
|
103437
|
+
{ ...options, format: cacheFormat },
|
|
103423
103438
|
signal,
|
|
103424
103439
|
config2,
|
|
103425
103440
|
lookup.entry.dir
|
|
@@ -103449,7 +103464,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
103449
103464
|
video.id,
|
|
103450
103465
|
video.mediaStart,
|
|
103451
103466
|
videoDuration,
|
|
103452
|
-
options,
|
|
103467
|
+
{ ...options, format: resolveFrameFormat(probedMeta, options.format) },
|
|
103453
103468
|
signal,
|
|
103454
103469
|
config2
|
|
103455
103470
|
);
|
|
@@ -103482,10 +103497,17 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
103482
103497
|
phaseBreakdown: breakdown
|
|
103483
103498
|
};
|
|
103484
103499
|
}
|
|
103485
|
-
function getFrameAtTime(extracted, globalTime, videoStart) {
|
|
103486
|
-
|
|
103500
|
+
function getFrameAtTime(extracted, globalTime, videoStart, loop = false, mediaStart = 0) {
|
|
103501
|
+
let localTime = globalTime - videoStart;
|
|
103487
103502
|
if (localTime < 0) return null;
|
|
103503
|
+
const loopDuration = Math.max(0, extracted.metadata.durationSeconds - mediaStart);
|
|
103504
|
+
if (loop && loopDuration > 0 && localTime >= loopDuration) {
|
|
103505
|
+
localTime %= loopDuration;
|
|
103506
|
+
}
|
|
103488
103507
|
const frameIndex = Math.floor(localTime * extracted.fps);
|
|
103508
|
+
if (loop && frameIndex >= extracted.totalFrames && extracted.totalFrames > 0) {
|
|
103509
|
+
return extracted.framePaths.get(extracted.totalFrames - 1) || null;
|
|
103510
|
+
}
|
|
103489
103511
|
if (frameIndex < 0 || frameIndex >= extracted.totalFrames) return null;
|
|
103490
103512
|
return extracted.framePaths.get(frameIndex) || null;
|
|
103491
103513
|
}
|
|
@@ -103495,8 +103517,8 @@ var FrameLookupTable = class {
|
|
|
103495
103517
|
activeVideoIds = /* @__PURE__ */ new Set();
|
|
103496
103518
|
startCursor = 0;
|
|
103497
103519
|
lastTime = null;
|
|
103498
|
-
addVideo(extracted, start, end, mediaStart) {
|
|
103499
|
-
this.videos.set(extracted.videoId, { extracted, start, end, mediaStart });
|
|
103520
|
+
addVideo(extracted, start, end, mediaStart, loop = false) {
|
|
103521
|
+
this.videos.set(extracted.videoId, { extracted, start, end, mediaStart, loop });
|
|
103500
103522
|
this.orderedVideos = Array.from(this.videos.entries()).map(([videoId, video]) => ({ videoId, ...video })).sort((a, b) => a.start - b.start);
|
|
103501
103523
|
this.resetActiveState();
|
|
103502
103524
|
}
|
|
@@ -103504,7 +103526,7 @@ var FrameLookupTable = class {
|
|
|
103504
103526
|
const video = this.videos.get(videoId);
|
|
103505
103527
|
if (!video) return null;
|
|
103506
103528
|
if (globalTime < video.start || globalTime >= video.end) return null;
|
|
103507
|
-
return getFrameAtTime(video.extracted, globalTime, video.start);
|
|
103529
|
+
return getFrameAtTime(video.extracted, globalTime, video.start, video.loop, video.mediaStart);
|
|
103508
103530
|
}
|
|
103509
103531
|
resetActiveState() {
|
|
103510
103532
|
this.activeVideoIds.clear();
|
|
@@ -103553,8 +103575,19 @@ var FrameLookupTable = class {
|
|
|
103553
103575
|
for (const videoId of this.activeVideoIds) {
|
|
103554
103576
|
const video = this.videos.get(videoId);
|
|
103555
103577
|
if (!video) continue;
|
|
103556
|
-
|
|
103578
|
+
let localTime = globalTime - video.start;
|
|
103579
|
+
const loopDuration = Math.max(0, video.extracted.metadata.durationSeconds - video.mediaStart);
|
|
103580
|
+
if (video.loop && loopDuration > 0 && localTime >= loopDuration) {
|
|
103581
|
+
localTime %= loopDuration;
|
|
103582
|
+
}
|
|
103557
103583
|
const frameIndex = Math.floor(localTime * video.extracted.fps);
|
|
103584
|
+
if (video.loop && frameIndex >= video.extracted.totalFrames) {
|
|
103585
|
+
const framePath2 = video.extracted.framePaths.get(video.extracted.totalFrames - 1);
|
|
103586
|
+
if (framePath2) {
|
|
103587
|
+
frames.set(videoId, { framePath: framePath2, frameIndex: video.extracted.totalFrames - 1 });
|
|
103588
|
+
}
|
|
103589
|
+
continue;
|
|
103590
|
+
}
|
|
103558
103591
|
if (frameIndex < 0 || frameIndex >= video.extracted.totalFrames) continue;
|
|
103559
103592
|
const framePath = video.extracted.framePaths.get(frameIndex);
|
|
103560
103593
|
if (!framePath) continue;
|
|
@@ -103588,7 +103621,7 @@ function createFrameLookupTable(videos, extracted) {
|
|
|
103588
103621
|
for (const ext of extracted) extractedMap.set(ext.videoId, ext);
|
|
103589
103622
|
for (const video of videos) {
|
|
103590
103623
|
const ext = extractedMap.get(video.id);
|
|
103591
|
-
if (ext) table.addVideo(ext, video.start, video.end, video.mediaStart);
|
|
103624
|
+
if (ext) table.addVideo(ext, video.start, video.end, video.mediaStart, video.loop);
|
|
103592
103625
|
}
|
|
103593
103626
|
return table;
|
|
103594
103627
|
}
|
|
@@ -109135,7 +109168,7 @@ async function compileHtmlFile(html, baseDir, downloadDir) {
|
|
|
109135
109168
|
let compiledHtml = resolutions.length > 0 ? injectDurations(staticCompiled, resolutions) : staticCompiled;
|
|
109136
109169
|
const preResolved = extractResolvedMedia(compiledHtml);
|
|
109137
109170
|
const clampResults = await Promise.all(
|
|
109138
|
-
preResolved.filter((el) => !!el.src).map(async (el) => {
|
|
109171
|
+
preResolved.filter((el) => !!el.src && !el.loop).map(async (el) => {
|
|
109139
109172
|
const { duration: maxDuration } = await resolveMediaDuration(
|
|
109140
109173
|
el.src,
|
|
109141
109174
|
el.mediaStart,
|
|
@@ -109743,6 +109776,7 @@ async function discoverMediaFromBrowser(page) {
|
|
|
109743
109776
|
const end = parseFloat(htmlEl.getAttribute("data-end") || "0");
|
|
109744
109777
|
const duration = parseFloat(htmlEl.getAttribute("data-duration") || "0");
|
|
109745
109778
|
const mediaStart = parseFloat(htmlEl.getAttribute("data-media-start") || "0");
|
|
109779
|
+
const loop = htmlEl.hasAttribute("loop");
|
|
109746
109780
|
const hasAudio = htmlEl.getAttribute("data-has-audio") === "true";
|
|
109747
109781
|
const volume = parseFloat(htmlEl.getAttribute("data-volume") || "1");
|
|
109748
109782
|
results.push({
|
|
@@ -109753,6 +109787,7 @@ async function discoverMediaFromBrowser(page) {
|
|
|
109753
109787
|
end,
|
|
109754
109788
|
duration,
|
|
109755
109789
|
mediaStart,
|
|
109790
|
+
loop,
|
|
109756
109791
|
hasAudio,
|
|
109757
109792
|
volume
|
|
109758
109793
|
});
|
|
@@ -110627,6 +110662,9 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110627
110662
|
if (el.hasAudio && !existing.hasAudio) {
|
|
110628
110663
|
existing.hasAudio = true;
|
|
110629
110664
|
}
|
|
110665
|
+
if (el.loop && !existing.loop) {
|
|
110666
|
+
existing.loop = true;
|
|
110667
|
+
}
|
|
110630
110668
|
}
|
|
110631
110669
|
} else {
|
|
110632
110670
|
composition.videos.push({
|
|
@@ -110635,6 +110673,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110635
110673
|
start: el.start,
|
|
110636
110674
|
end: el.end,
|
|
110637
110675
|
mediaStart: el.mediaStart,
|
|
110676
|
+
loop: el.loop,
|
|
110638
110677
|
hasAudio: el.hasAudio
|
|
110639
110678
|
});
|
|
110640
110679
|
existingVideoIds.add(el.id);
|