splatoon3.ink/app/screenshots/ScreenshotHelper.mjs
2024-11-17 16:29:00 -08:00

111 lines
2.4 KiB
JavaScript

import { URL } from 'url';
import puppeteer from 'puppeteer-core';
import HttpServer from './HttpServer.mjs';
const defaultViewport = {
// Using a 16:9 ratio here by default to match Twitter's image card dimensions
width: 1200,
height: 675,
deviceScaleFactor: 2,
};
export default class ScreenshotHelper
{
/** @type {HttpServer} */
#httpServer = null;
/** @type {puppeteer.Browser} */
#browser = null;
/** @type {puppeteer.Page} */
#page = null;
defaultParams = null;
get isOpen() {
return !!this.#browser;
}
/** @type {puppeteer.Page} */
get page() {
return this.#page;
}
async open() {
await this.close();
// Start the HTTP server
this.#httpServer = new HttpServer;
await this.#httpServer.open();
// Connect to Browserless
this.#browser = await puppeteer.connect({
browserWSEndpoint: process.env.BROWSERLESS_ENDPOINT,
});
// Create a new page and set the viewport
this.#page = await this.#browser.newPage();
await this.applyViewport();
}
async applyViewport(viewport = {}) {
if (this.#page) {
await this.#page.setViewport({
...defaultViewport,
...viewport,
});
}
}
async capture(path, options = {}) {
if (!this.isOpen) {
await this.open();
}
await this.applyViewport(options.viewport);
// Navigate to the URL
let host = process.env.SCREENSHOT_HOST || 'localhost';
let url = new URL(`http://${host}:${this.#httpServer.port}/screenshots/`);
url.hash = path;
let params = {
...this.defaultParams,
...options.params,
};
if (params) {
// We can't use url.searchParams because they need to come after the hash
url.hash += '?';
url.hash += Object.keys(params)
.map(key => `${key}=${params[key]}`)
.join('&');
}
await this.#page.goto(url, {
waitUntil: 'networkidle0', // Wait until the network is idle
});
// Wait an additional 1000ms
await this.#page.waitForNetworkIdle({ idleTime: 1000 });
// Take the screenshot
return await this.#page.screenshot();
}
async close() {
if (this.#httpServer) {
await this.#httpServer.close();
}
this.#httpServer = null;
if (this.#page) {
await this.#page.close();
}
this.#page = null;
if (this.#browser) {
await this.#browser.close();
}
this.#browser = null;
}
}