Skip to content

Commit 20d0829

Browse files
authored
Merge pull request #228 from CrazyWolf13/patch-1
Really fix the screenshot api endpoint
2 parents 9088384 + bbf519e commit 20d0829

File tree

1 file changed

+90
-12
lines changed

1 file changed

+90
-12
lines changed

api/screenshot.js

+90-12
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,111 @@
11
import puppeteer from 'puppeteer-core';
22
import chromium from 'chrome-aws-lambda';
33
import middleware from './_common/middleware.js';
4+
import { exec } from 'child_process';
5+
import { promises as fs } from 'fs';
6+
import path from 'path';
7+
import pkg from 'uuid';
8+
const { v4: uuidv4 } = pkg;
49

5-
const screenshotHandler = async (targetUrl) => {
10+
// Helper function for direct chromium screenshot as fallback
11+
const directChromiumScreenshot = async (url) => {
12+
console.log(`[DIRECT-SCREENSHOT] Starting direct screenshot process for URL: ${url}`);
13+
14+
// Create a tmp filename
15+
const tmpDir = '/tmp';
16+
const uuid = uuidv4();
17+
const screenshotPath = path.join(tmpDir, `screenshot-${uuid}.png`);
18+
19+
console.log(`[DIRECT-SCREENSHOT] Will save screenshot to: ${screenshotPath}`);
20+
21+
return new Promise((resolve, reject) => {
22+
const chromePath = process.env.CHROME_PATH || '/usr/bin/chromium';
23+
const command = `${chromePath} --headless --disable-gpu --no-sandbox --screenshot=${screenshotPath} "${url}"`;
24+
25+
console.log(`[DIRECT-SCREENSHOT] Executing command: ${command}`);
26+
27+
exec(command, async (error, stdout, stderr) => {
28+
if (error) {
29+
console.error(`[DIRECT-SCREENSHOT] Error executing Chromium: ${error.message}`);
30+
return reject(error);
31+
}
32+
33+
try {
34+
// Read screenshot
35+
const screenshotData = await fs.readFile(screenshotPath);
36+
console.log(`[DIRECT-SCREENSHOT] Read ${screenshotData.length} bytes from screenshot file`);
37+
38+
// Convert base64
39+
const base64Data = screenshotData.toString('base64');
40+
41+
// Clean
42+
await fs.unlink(screenshotPath).catch(err =>
43+
console.warn(`[DIRECT-SCREENSHOT] Failed to delete temp file: ${err.message}`)
44+
);
45+
46+
resolve(base64Data);
47+
} catch (readError) {
48+
console.error(`[DIRECT-SCREENSHOT] Error reading screenshot: ${readError.message}`);
49+
reject(readError);
50+
}
51+
});
52+
});
53+
};
654

55+
const screenshotHandler = async (targetUrl) => {
56+
console.log(`[SCREENSHOT] Request received for URL: ${targetUrl}`);
57+
758
if (!targetUrl) {
59+
console.error('[SCREENSHOT] URL is missing from queryStringParameters');
860
throw new Error('URL is missing from queryStringParameters');
961
}
10-
62+
1163
if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) {
1264
targetUrl = 'http://' + targetUrl;
1365
}
14-
66+
1567
try {
1668
new URL(targetUrl);
1769
} catch (error) {
70+
console.error(`[SCREENSHOT] URL provided is invalid: ${targetUrl}`);
1871
throw new Error('URL provided is invalid');
1972
}
2073

74+
// First try direct Chromium
75+
try {
76+
console.log(`[SCREENSHOT] Using direct Chromium method for URL: ${targetUrl}`);
77+
const base64Screenshot = await directChromiumScreenshot(targetUrl);
78+
console.log(`[SCREENSHOT] Direct screenshot successful`);
79+
return { image: base64Screenshot };
80+
} catch (directError) {
81+
console.error(`[SCREENSHOT] Direct screenshot method failed: ${directError.message}`);
82+
console.log(`[SCREENSHOT] Falling back to puppeteer method...`);
83+
}
84+
85+
// fall back puppeteer
2186
let browser = null;
2287
try {
23-
browser = await puppeteer.launch({
88+
console.log(`[SCREENSHOT] Launching puppeteer browser`);
89+
browser = await puppeteer.launch({
2490
args: [...chromium.args, '--no-sandbox'], // Add --no-sandbox flag
2591
defaultViewport: { width: 800, height: 600 },
26-
executablePath: process.env.CHROME_PATH || await chromium.executablePath,
27-
headless: chromium.headless,
92+
executablePath: process.env.CHROME_PATH || '/usr/bin/chromium',
93+
headless: true,
2894
ignoreHTTPSErrors: true,
2995
ignoreDefaultArgs: ['--disable-extensions'],
3096
});
31-
97+
98+
console.log(`[SCREENSHOT] Creating new page`);
3299
let page = await browser.newPage();
33-
100+
101+
console.log(`[SCREENSHOT] Setting page preferences`);
34102
await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]);
35103
page.setDefaultNavigationTimeout(8000);
104+
105+
console.log(`[SCREENSHOT] Navigating to URL: ${targetUrl}`);
36106
await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
37-
107+
108+
console.log(`[SCREENSHOT] Checking if body element exists`);
38109
await page.evaluate(() => {
39110
const selector = 'body';
40111
return new Promise((resolve, reject) => {
@@ -45,14 +116,21 @@ const screenshotHandler = async (targetUrl) => {
45116
resolve();
46117
});
47118
});
48-
119+
120+
console.log(`[SCREENSHOT] Taking screenshot`);
49121
const screenshotBuffer = await page.screenshot();
122+
123+
console.log(`[SCREENSHOT] Converting screenshot to base64`);
50124
const base64Screenshot = screenshotBuffer.toString('base64');
51-
125+
126+
console.log(`[SCREENSHOT] Screenshot complete, returning image`);
52127
return { image: base64Screenshot };
53-
128+
} catch (error) {
129+
console.error(`[SCREENSHOT] Puppeteer screenshot failed: ${error.message}`);
130+
throw error;
54131
} finally {
55132
if (browser !== null) {
133+
console.log(`[SCREENSHOT] Closing browser`);
56134
await browser.close();
57135
}
58136
}

0 commit comments

Comments
 (0)