Merge pull request #1820 from heygen-com/fix/snapshot-remote-video-frames

fix(cli): snapshot renders remote http(s) <video> frames (not just local files)
This commit is contained in:
Xuanru Li
2026-06-30 16:16:19 -07:00
committed by GitHub
+23 -5
View File
@@ -355,23 +355,41 @@ async function captureSnapshots(
const updates: Array<{ videoId: string; dataUri: string }> = [];
for (const v of active) {
let filePath: string | null = null;
// Resolve the <video> src to an FFmpeg input. Prefer a project-local
// file (fast, sandboxed); fall back to the absolute http(s) URL for
// remote assets (e.g. an S3-hosted clip embedded by an upstream agent)
// — FFmpeg reads http(s) input directly, and Chrome-headless can't seek
// it either, so without this those videos render blank in snapshots.
let ffmpegInput: string | null = null;
let inputIsLocal = false;
try {
const url = new URL(v.src);
const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
const candidate = resolve(projectDir, decodedPath);
const rel = relative(projectDir, candidate);
if (!rel.startsWith("..") && !isAbsolute(rel) && existsSync(candidate)) {
filePath = candidate;
ffmpegInput = candidate;
inputIsLocal = true;
} else if (url.protocol === "http:" || url.protocol === "https:") {
ffmpegInput = url.href;
}
} catch {
/* unresolvable src (e.g. blob:, data:) — skip */
}
if (!filePath) continue;
if (!ffmpegInput) continue;
// VP9-alpha detection shells out to ffprobe, which has no timeout.
// Only probe local files (filesystem-bounded); for remote URLs skip it
// (pass false) so a stalled host can't wedge snapshot in ffprobe before
// the bounded extractVideoFrameToBuffer below ever runs. Remote
// VP9-alpha overlays aren't a current path — revisit with a bounded
// ffprobe if one appears.
const useVp9AlphaDecoder = inputIsLocal
? await shouldUseVp9AlphaDecoder(ffmpegInput)
: false;
const png = await extractVideoFrameToBuffer(
filePath,
ffmpegInput,
Math.max(0, v.relTime),
await shouldUseVp9AlphaDecoder(filePath),
useVp9AlphaDecoder,
);
if (!png) continue;
updates.push({