Skip to content

Commit 4d38d7c

Browse files
authored
Merge pull request #17 from fxhash/feat/revert-programmatic-gif
Revert "implement programmatic gif capture"
2 parents aca53cf + 1918b04 commit 4d38d7c

File tree

1 file changed

+46
-132
lines changed

1 file changed

+46
-132
lines changed

index.js

Lines changed: 46 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const ERRORS = {
7777
// the different capture modes
7878
const CAPTURE_MODES = ["CANVAS", "VIEWPORT"]
7979
// the list of accepted trigger modes
80-
const TRIGGER_MODES = ["DELAY", "FN_TRIGGER", "FN_TRIGGER_GIF"]
80+
const TRIGGER_MODES = ["DELAY", "FN_TRIGGER"]
8181

8282
//
8383
// UTILITY FUNCTIONS
@@ -94,7 +94,7 @@ function isUrlValid(url) {
9494
}
9595

9696
// is a trigger valid ? looks at the trigger mode and trigger settings
97-
function isTriggerValid(triggerMode, delay, playbackFps) {
97+
function isTriggerValid(triggerMode, delay) {
9898
if (!TRIGGER_MODES.includes(triggerMode)) {
9999
return false
100100
}
@@ -106,15 +106,8 @@ function isTriggerValid(triggerMode, delay, playbackFps) {
106106
delay >= DELAY_MIN &&
107107
delay <= DELAY_MAX
108108
)
109-
} else if (triggerMode === "FN_TRIGGER_GIF") {
110-
return (
111-
typeof playbackFps !== undefined &&
112-
!isNaN(playbackFps) &&
113-
playbackFps >= GIF_DEFAULTS.MIN_FPS &&
114-
playbackFps <= GIF_DEFAULTS.MAX_FPS
115-
)
116109
} else if (triggerMode === "FN_TRIGGER") {
117-
// fn trigger and fn trigger gif don't need any params
110+
// fn trigger doesn't need any param
118111
return true
119112
}
120113
}
@@ -330,7 +323,6 @@ const resizeCanvas = async (image, resX, resY) => {
330323
}
331324
const performCapture = async (
332325
mode,
333-
triggerMode,
334326
page,
335327
canvasSelector,
336328
resX,
@@ -345,22 +337,14 @@ const performCapture = async (
345337
// if viewport mode, use the native puppeteer page.screenshot
346338
if (mode === "VIEWPORT") {
347339
// we simply take a capture of the viewport
348-
return captureViewport(
349-
page,
350-
triggerMode,
351-
gif,
352-
frameCount,
353-
captureInterval,
354-
playbackFps
355-
)
340+
return captureViewport(page, gif, frameCount, captureInterval, playbackFps)
356341
}
357342
// if the mode is canvas, we need to execute som JS on the client to select
358343
// the canvas and generate a dataURL to bridge it in here
359344
else if (mode === "CANVAS") {
360345
const canvas = await captureCanvas(
361346
page,
362347
canvasSelector,
363-
triggerMode,
364348
gif,
365349
frameCount,
366350
captureInterval,
@@ -435,7 +419,7 @@ const validateParams = ({
435419
if (!url || !mode) throw ERRORS.MISSING_PARAMETERS
436420
if (!isUrlValid(url)) throw ERRORS.UNSUPPORTED_URL
437421
if (!CAPTURE_MODES.includes(mode)) throw ERRORS.INVALID_PARAMETERS
438-
if (!isTriggerValid(triggerMode, delay, playbackFps))
422+
if (!isTriggerValid(triggerMode, delay))
439423
throw ERRORS.INVALID_TRIGGER_PARAMETERS
440424

441425
if (gif && !validateGifParams(frameCount, captureInterval, playbackFps))
@@ -472,21 +456,29 @@ const validateParams = ({
472456
}
473457
}
474458

475-
async function captureFramesWithTiming(
476-
captureFrameFunction,
459+
async function captureViewport(
460+
page,
461+
isGif,
477462
frameCount,
478-
captureInterval
463+
captureInterval,
464+
playbackFps
479465
) {
466+
if (!isGif) {
467+
return await page.screenshot()
468+
}
469+
480470
const frames = []
481471
let lastCaptureStart = performance.now()
482472

483473
for (let i = 0; i < frameCount; i++) {
484474
// Record start time of screenshot operation
485475
const captureStart = performance.now()
486476

487-
// Use the provided capture function to get the frame
488-
const frame = await captureFrameFunction()
489-
frames.push(frame)
477+
// Capture raw pixels
478+
const frameBuffer = await page.screenshot({
479+
encoding: "binary",
480+
})
481+
frames.push(frameBuffer)
490482

491483
// Calculate how long the capture took
492484
const captureDuration = performance.now() - captureStart
@@ -510,88 +502,6 @@ async function captureFramesWithTiming(
510502
lastCaptureStart = performance.now()
511503
}
512504

513-
return frames
514-
}
515-
516-
async function captureFramesProgrammatically(page, captureFrameFunction) {
517-
const frames = []
518-
519-
page.on("console", msg => {
520-
console.log("BROWSER:", msg.text())
521-
})
522-
523-
// set up the event listener and capture loop
524-
await page.exposeFunction("captureFrame", async () => {
525-
const frame = await captureFrameFunction()
526-
frames.push(frame)
527-
console.log(`programmatic frame ${frames.length} captured`)
528-
return frames.length
529-
})
530-
531-
// wait for events in browser context
532-
await page.evaluate(
533-
function (maxFrames, delayMax) {
534-
return new Promise(function (resolve) {
535-
const handleFrameCapture = async event => {
536-
const frameCount = await window.captureFrame()
537-
538-
console.log(JSON.stringify(event))
539-
console.log(JSON.stringify({ frameCount, maxFrames }))
540-
console.log(
541-
JSON.stringify({ isLastFrame: event.detail?.isLastFrame })
542-
)
543-
if (event.detail?.isLastFrame || frameCount >= maxFrames) {
544-
window.removeEventListener(
545-
"fxhash-capture-frame",
546-
handleFrameCapture
547-
)
548-
resolve()
549-
}
550-
}
551-
552-
window.addEventListener("fxhash-capture-frame", handleFrameCapture)
553-
554-
// timeout fallback
555-
setTimeout(() => {
556-
window.removeEventListener("fxhash-capture-frame", handleFrameCapture)
557-
resolve()
558-
}, delayMax)
559-
})
560-
},
561-
GIF_DEFAULTS.MAX_FRAMES,
562-
DELAY_MAX
563-
)
564-
565-
return frames
566-
}
567-
568-
async function captureViewport(
569-
page,
570-
triggerMode,
571-
isGif,
572-
frameCount,
573-
captureInterval,
574-
playbackFps
575-
) {
576-
if (!isGif) {
577-
return await page.screenshot()
578-
}
579-
580-
const captureViewportFrame = async () => {
581-
return await page.screenshot({
582-
encoding: "binary",
583-
})
584-
}
585-
586-
const frames =
587-
triggerMode === "FN_TRIGGER_GIF"
588-
? await captureFramesProgrammatically(page, captureViewportFrame)
589-
: await captureFramesWithTiming(
590-
captureViewportFrame,
591-
frameCount,
592-
captureInterval
593-
)
594-
595505
const viewport = page.viewport()
596506
return await captureFramesToGif(
597507
frames,
@@ -604,7 +514,6 @@ async function captureViewport(
604514
async function captureCanvas(
605515
page,
606516
canvasSelector,
607-
triggerMode,
608517
isGif,
609518
frameCount,
610519
captureInterval,
@@ -623,24 +532,36 @@ async function captureCanvas(
623532
return Buffer.from(pureBase64, "base64")
624533
}
625534

626-
const captureCanvasFrame = async () => {
535+
const frames = []
536+
let lastCaptureStart = Date.now()
537+
538+
for (let i = 0; i < frameCount; i++) {
539+
const captureStart = Date.now()
540+
627541
// Get raw pixel data from canvas
628542
const base64 = await page.$eval(canvasSelector, el => {
629543
if (!el || el.tagName !== "CANVAS") return null
630544
return el.toDataURL()
631545
})
632-
if (!base64) throw new Error("Canvas capture failed")
633-
return base64
634-
}
546+
if (!base64) throw null
547+
frames.push(base64)
635548

636-
const frames =
637-
triggerMode === "FN_TRIGGER_GIF"
638-
? await captureFramesProgrammatically(page, captureCanvasFrame)
639-
: await captureFramesWithTiming(
640-
captureCanvasFrame,
641-
frameCount,
642-
captureInterval
643-
)
549+
// Calculate timing adjustments
550+
const captureDuration = Date.now() - captureStart
551+
const adjustedInterval = Math.max(0, captureInterval - captureDuration)
552+
553+
console.log(`Frame ${i + 1}/${frameCount}:`, {
554+
captureDuration,
555+
adjustedInterval,
556+
totalFrameTime: Date.now() - lastCaptureStart,
557+
})
558+
559+
if (adjustedInterval > 0) {
560+
await sleep(adjustedInterval)
561+
}
562+
563+
lastCaptureStart = Date.now()
564+
}
644565

645566
const dimensions = await page.$eval(canvasSelector, el => ({
646567
width: el.width,
@@ -750,7 +671,6 @@ exports.handler = async (event, context) => {
750671
const processCapture = async () => {
751672
const capture = await performCapture(
752673
mode,
753-
triggerMode,
754674
page,
755675
canvasSelector,
756676
resX,
@@ -767,16 +687,10 @@ exports.handler = async (event, context) => {
767687
return upload
768688
}
769689

770-
if (triggerMode === "FN_TRIGGER_GIF") {
771-
// for FN_TRIGGER_GIF mode, skip preview waiting entirely
772-
// the capture functions will handle event listening internally
773-
console.log("Using FN_TRIGGER_GIF mode - skipping preview wait")
690+
if (useFallbackCaptureOnTimeout) {
691+
await waitPreviewWithFallback(context, triggerMode, page, delay)
774692
} else {
775-
if (useFallbackCaptureOnTimeout) {
776-
await waitPreviewWithFallback(context, triggerMode, page, delay)
777-
} else {
778-
await waitPreview(triggerMode, page, delay)
779-
}
693+
await waitPreview(triggerMode, page, delay)
780694
}
781695

782696
httpResponse = await processCapture()

0 commit comments

Comments
 (0)