Initial commit
This commit is contained in:
commit
690d825f9a
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
package-lock.json
|
|
@ -0,0 +1,25 @@
|
||||||
|
const { parseRequest } = require('./parser');
|
||||||
|
const { getScreenshot } = require('./chromium');
|
||||||
|
const { getHtml } = require('./template');
|
||||||
|
const { writeTempFile, pathToFileURL } = require('./file');
|
||||||
|
|
||||||
|
module.exports = async function (req, res) {
|
||||||
|
try {
|
||||||
|
let { type = 'png', text = 'Hello' } = parseRequest(req);
|
||||||
|
const name = decodeURIComponent(text);
|
||||||
|
const html = getHtml(name);
|
||||||
|
const filePath = await writeTempFile(name, html);
|
||||||
|
const fileUrl = pathToFileURL(filePath);
|
||||||
|
const file = await getScreenshot(fileUrl, type);
|
||||||
|
res.statusCode = 200;
|
||||||
|
res.setHeader('Content-Type', `image/${type}`);
|
||||||
|
res.setHeader('Cache-Control', `public, immutable, no-transform, max-age=31536000`);
|
||||||
|
res.end(file);
|
||||||
|
} catch (e) {
|
||||||
|
res.statusCode = 500;
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
res.end('<h1>Server Error</h1><p>Sorry, there was a problem</p>');
|
||||||
|
console.error(e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
const chrome = require('chrome-aws-lambda');
|
||||||
|
const puppeteer = require('puppeteer-core');
|
||||||
|
|
||||||
|
async function getScreenshot(url, type) {
|
||||||
|
const browser = await puppeteer.launch({
|
||||||
|
args: chrome.args,
|
||||||
|
executablePath: await chrome.executablePath,
|
||||||
|
headless: chrome.headless,
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.setViewport({ width: 2048, height: 1170 });
|
||||||
|
await page.goto(url);
|
||||||
|
const file = await page.screenshot({ type });
|
||||||
|
await browser.close();
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { getScreenshot };
|
|
@ -0,0 +1,5 @@
|
||||||
|
const { createServer } = require('http');
|
||||||
|
const PORT = 3000;
|
||||||
|
const handleServer = require('./card');
|
||||||
|
const handleListen = () => console.log(`Listening on ${PORT}...`);
|
||||||
|
createServer(handleServer).listen(PORT, handleListen);
|
|
@ -0,0 +1,21 @@
|
||||||
|
const { writeFile } = require('fs');
|
||||||
|
const { join } = require('path');
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const writeFileAsync = promisify(writeFile);
|
||||||
|
const { tmpdir } = require('os');
|
||||||
|
const { URL } = require('url');
|
||||||
|
|
||||||
|
async function writeTempFile(name, contents) {
|
||||||
|
const randomPath = join(tmpdir(), `${name}.html`);
|
||||||
|
console.log('Writing file to ' + randomPath);
|
||||||
|
await writeFileAsync(randomPath, contents);
|
||||||
|
return randomPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathToFileURL(path) {
|
||||||
|
const { href } = new URL(path, 'file:');
|
||||||
|
console.log('File url is ' + href);
|
||||||
|
return href;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { writeTempFile, pathToFileURL }
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "og-image",
|
||||||
|
"alias": "og-image.now.sh",
|
||||||
|
"version": 2,
|
||||||
|
"builds": [
|
||||||
|
{ "src": "card.js", "use": "@now/node", "config": { "maxLambdaSize": "40mb" } }
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{ "src": "/(.*)", "dest": "/card.js" }
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "og-image",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Generate an open graph image for twitter/facebook/etc",
|
||||||
|
"main": "card.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "node dev.js"
|
||||||
|
},
|
||||||
|
"author": "styfle",
|
||||||
|
"repository": "github:styfle/og-image",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"chrome-aws-lambda": "1.11.1",
|
||||||
|
"puppeteer-core": "1.11.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
const { parse } = require('url');
|
||||||
|
|
||||||
|
function parseRequest(req) {
|
||||||
|
const { pathname = '/' } = parse(req.url);
|
||||||
|
console.log('Hit ' + pathname);
|
||||||
|
const arr = pathname.slice(1).split('.');
|
||||||
|
const type = arr.pop();
|
||||||
|
const text = arr.join('.');
|
||||||
|
return { type, text };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { parseRequest }
|
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
const logo = 'https://assets.zeit.co/image/upload/front/assets/design/now-black.svg';
|
||||||
|
|
||||||
|
const css = `
|
||||||
|
body {
|
||||||
|
background: white;
|
||||||
|
background-image: radial-gradient(lightgray 5%, transparent 0);
|
||||||
|
background-size: 100px 100px;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 225px;
|
||||||
|
height: 225px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
margin: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||||
|
font-size: 75px;
|
||||||
|
font-weight: bold;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
function getHtml(text) {
|
||||||
|
return `<html>
|
||||||
|
<style>
|
||||||
|
${css}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<div class="spacer">
|
||||||
|
<img class="logo" src="${logo}" />
|
||||||
|
<div class="spacer">
|
||||||
|
<div class="heading">${text}</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { getHtml }
|
Loading…
Reference in New Issue