webstack-screenshot
Version:
📸网站截图 API | Website Screenshot API
233 lines (223 loc) • 7.9 kB
JavaScript
;
const screenshot = require('./shared/webstack-screenshot.C_kd1VBn.cjs');
const node_buffer = require('node:buffer');
const puppeteer$1 = require('puppeteer-core');
const process = require('node:process');
const sparticuzPuppeteer = require('@sparticuz/chromium');
const puppeteer = require('puppeteer');
const http = require('node:http');
const bodyData = require('body-data');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const puppeteer__default$1 = /*#__PURE__*/_interopDefaultCompat(puppeteer$1);
const process__default = /*#__PURE__*/_interopDefaultCompat(process);
const sparticuzPuppeteer__default = /*#__PURE__*/_interopDefaultCompat(sparticuzPuppeteer);
const puppeteer__default = /*#__PURE__*/_interopDefaultCompat(puppeteer);
const http__default = /*#__PURE__*/_interopDefaultCompat(http);
const args = (() => {
const puppeteerFlags = [
"--allow-pre-commit-input",
"--disable-background-networking",
"--disable-background-timer-throttling",
"--disable-backgrounding-occluded-windows",
"--disable-breakpad",
"--disable-client-side-phishing-detection",
"--disable-component-extensions-with-background-pages",
"--disable-component-update",
"--disable-default-apps",
"--disable-dev-shm-usage",
"--disable-extensions",
"--disable-hang-monitor",
"--disable-ipc-flooding-protection",
"--disable-popup-blocking",
"--disable-prompt-on-repost",
"--disable-renderer-backgrounding",
"--disable-sync",
"--enable-automation",
// TODO(sadym): remove '--enable-blink-features=IdleDetection' once
// IdleDetection is turned on by default.
"--enable-blink-features=IdleDetection",
"--export-tagged-pdf",
"--force-color-profile=srgb",
"--metrics-recording-only",
"--no-first-run",
"--password-store=basic",
"--use-mock-keychain"
];
const puppeteerDisableFeatures = [
"Translate",
"BackForwardCache",
// AcceptCHFrame disabled because of crbug.com/1348106.
"AcceptCHFrame",
"MediaRouter",
"OptimizationHints"
];
const puppeteerEnableFeatures = ["NetworkServiceInProcess2"];
const chromiumFlags = [
"--disable-domain-reliability",
"--disable-print-preview",
"--disable-speech-api",
"--disk-cache-size=33554432",
"--mute-audio",
"--no-default-browser-check",
"--no-pings",
// Needs to be single-process to avoid `prctl(PR_SET_NO_NEW_PRIVS) failed` error
"--single-process"
];
const chromiumDisableFeatures = ["AudioServiceOutOfProcess", "IsolateOrigins", "site-per-process"];
const chromiumEnableFeatures = ["SharedArrayBuffer"];
const graphicsFlags = [
"--hide-scrollbars",
"--ignore-gpu-blocklist",
"--in-process-gpu",
// https://chromium.googlesource.com/chromium/src/+/main/docs/gpu/swiftshader.md
"--use-gl=angle",
"--use-angle=swiftshader",
// https://source.chromium.org/search?q=lang:cpp+symbol:kWindowSize&ss=chromium
"--window-size=1920,1080"
];
const insecureFlags = [
"--allow-running-insecure-content",
"--disable-setuid-sandbox",
"--disable-site-isolation-trials",
"--disable-web-security",
"--no-sandbox",
// https://source.chromium.org/search?q=lang:cpp+symbol:kNoZygote&ss=chromium
"--no-zygote"
];
return [
...puppeteerFlags,
...chromiumFlags,
`--disable-features=${[...puppeteerDisableFeatures, ...chromiumDisableFeatures].join(",")}`,
`--enable-features=${[...puppeteerEnableFeatures, ...chromiumEnableFeatures].join(",")}`,
...graphicsFlags,
...insecureFlags,
"--headless='new'"
];
})();
const { WEBSTACK_SCREENSHOT_PUPPETEER_EXECUTABLE_PATH, WEBSTACK_SCREENSHOT_IS_AWS_LAMBDA, WEBSTACK_SCREENSHOT_FONTS } = process__default.env;
function isNumber(value) {
return !Number.isNaN(value);
}
function isHttp(url) {
return /^https?:\/\//.test(url);
}
async function getLaunch(options = {}) {
const opts = {
...options,
headless: "shell",
executablePath: puppeteer__default.executablePath()
};
if (WEBSTACK_SCREENSHOT_IS_AWS_LAMBDA) {
if (WEBSTACK_SCREENSHOT_FONTS) {
const fonts = WEBSTACK_SCREENSHOT_FONTS.split(",").filter(Boolean).map((font) => sparticuzPuppeteer__default.font(font));
await Promise.all(fonts);
}
opts.args = sparticuzPuppeteer__default.args;
opts.executablePath = await sparticuzPuppeteer__default.executablePath();
}
if (WEBSTACK_SCREENSHOT_PUPPETEER_EXECUTABLE_PATH) {
opts.executablePath = WEBSTACK_SCREENSHOT_PUPPETEER_EXECUTABLE_PATH;
}
return opts;
}
function cache(cache2) {
if (cache2 === false || cache2 === 0) {
return void 0;
}
const sec = Math.abs(cache2);
const daySec = 86400;
const cacheKey = "public, no-transform, s-maxage=$, max-age=$";
if (!cache2) {
return cacheKey.replace(/\$/g, daySec.toString());
}
if (isNumber(sec)) {
return cacheKey.replace(/\$/g, sec.toString());
}
return void 0;
}
let browser, page;
async function getScreenshot(data) {
try {
data.url = isHttp(data.url) ? data.url : `http://${data.url}`;
if (!browser) {
const launchOpt = await getLaunch({});
browser = await puppeteer__default$1.launch(launchOpt);
}
const screenshot$1 = screenshot.Screenshot.getInstance();
page = await browser.newPage();
const buffer = await screenshot$1.getScreenshot(page, data);
await new Promise((r) => setTimeout(r, (data.await || 0) + 1e3));
return buffer;
} catch (error) {
console.error(error);
if (browser) {
browser.close();
browser = null;
}
} finally {
if (page) {
await page.close();
page = null;
}
}
return node_buffer.Buffer.from("");
}
async function serverless(req, res) {
console.log("NODE.js", process__default.version);
if (req.url === "/favicon.ico") {
res.end();
return;
}
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Content-Type", "application/json; charset=utf-8");
try {
const { params, body } = await bodyData.bodyData(req);
const data = req.method?.toUpperCase() === "POST" ? body : params;
if (!data.url) {
const projectUrl = "https://github.com/Lete114/WebStack-Screenshot#properties";
const msg = { msg: `URL not detected , Using parameters: ${projectUrl}` };
res.end(JSON.stringify(msg));
return;
}
if (!isHttp(data.url)) {
const msg = { msg: "URL must start with http:// or https://" };
res.end(JSON.stringify(msg));
return;
}
const content = await getScreenshot(data);
const cacheResult = cache(data.cache);
if (cacheResult) {
res.setHeader("Cache-Control", cacheResult);
}
const instance = screenshot.Screenshot.getInstance();
const options = instance.parse(data);
if (options.encoding === "base64") {
const base64 = `data:image/${options.type};base64,${content}`;
res.end(JSON.stringify({ data: base64 }));
} else {
res.setHeader("Content-Type", `image/${options.type}`);
res.write(content, options.encoding);
}
res.end();
} catch (error) {
console.error(error);
res.end(JSON.stringify({ msg: "Screenshot failed" }));
}
}
const PORT = process__default.env.WEBSTACK_SCREENSHOT_PORT || process__default.env.PORT || 6870;
function startServer(port = PORT) {
const server = http__default.createServer(serverless);
server.listen(port, () => {
console.log(`Service is up and running port, http://127.0.0.1:${port}`);
});
}
exports.DEFAULT_VIEWPORT = screenshot.DEFAULT_VIEWPORT;
exports.Screenshot = screenshot.Screenshot;
exports.args = args;
exports.cache = cache;
exports.getLaunch = getLaunch;
exports.getScreenshot = getScreenshot;
exports.isHttp = isHttp;
exports.isNumber = isNumber;
exports.serverless = serverless;
exports.startServer = startServer;