switch to puppeteer

This commit is contained in:
hazycora 2023-12-21 08:21:41 -06:00
parent 92b6846bbb
commit 6e3bad10f8
No known key found for this signature in database
GPG key ID: 215AF1F81F86940E
6 changed files with 611 additions and 667 deletions

143
assets/DMSans/style.css Normal file
View file

@ -0,0 +1,143 @@
@font-face {
font-family: 'DM Sans';
src: url('DMSans-SemiBoldItalic.ttf') format('truetype');
font-weight: 600;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-Thin.ttf') format('truetype');
font-weight: 100;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-Light.ttf') format('truetype');
font-weight: 300;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-ThinItalic.ttf') format('truetype');
font-weight: 100;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-Medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-Regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-LightItalic.ttf') format('truetype');
font-weight: 300;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-MediumItalic.ttf') format('truetype');
font-weight: 500;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-SemiBold.ttf') format('truetype');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-ExtraLightItalic.ttf') format('truetype');
font-weight: 200;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-BlackItalic.ttf') format('truetype');
font-weight: 900;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-Italic.ttf') format('truetype');
font-weight: normal;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-ExtraBold.ttf') format('truetype');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-ExtraBoldItalic.ttf') format('truetype');
font-weight: bold;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-Black.ttf') format('truetype');
font-weight: 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-Bold.ttf') format('truetype');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-BoldItalic.ttf') format('truetype');
font-weight: bold;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'DM Sans';
src: url('DMSans-ExtraLight.ttf') format('truetype');
font-weight: 200;
font-style: normal;
font-display: swap;
}

View file

@ -1,3 +1,8 @@
@import url('/assets/DMSans/style.css');
body {
font-family: 'DM Sans', sans-serif;
margin: 0;
}
div {
display: flex;
}
@ -76,6 +81,7 @@ p {
-webkit-box-orient: vertical;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
line-clamp: 2;
}
.is-debug .description {
display: block;

View file

@ -1,35 +1,72 @@
import html2png, { renderHTML as inline } from '@besties/html2png'
import puppeteer from 'puppeteer'
import fs from 'node:fs'
const style = fs.readFileSync('./assets/style.css', 'utf8')
const browser = await puppeteer.launch({
defaultViewport: {
width: 1200,
height: 600
},
headless: 'new',
// slowMo: 250,
args: [
// TODO: fix this
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-setuid-sandbox',
'--no-sandbox'
]
})
async function wait() {
const selectors = [...document.querySelectorAll('img')]
await Promise.all([
document.fonts.ready,
...selectors.map(img => {
// Image has already finished loading, lets see if it worked
if (img.complete) {
// Image loaded and has presence
if (img.naturalHeight !== 0) return
// Image failed, so it has no height
throw new Error('Image failed to load')
}
// Image hasnt loaded yet, added an event listener to know when it does
return new Promise((resolve, reject) => {
img.addEventListener('load', resolve)
img.addEventListener('error', reject)
})
})
])
}
export async function renderPage(html) {
const page = await browser.newPage()
try {
await page.setContent(html, {
waitUntil: 'domcontentloaded'
})
await page.evaluate(wait)
const buffer = await page.screenshot({
type: 'png',
encoding: 'binary'
})
await page.close()
return buffer
} catch {
await page.close()
throw new Error('Failed to render page')
}
}
export default async function (html, options = {}) {
return html2png(`<style>${style}</style>${html}`, options)
if (options.format == 'html') {
return await renderHtml(html)
}
return renderPage(`<style>${style}</style>${html}`)
}
export async function renderHtml(html) {
const styleNow = await fs.promises.readFile('./assets/style.css', 'utf8')
return (
`<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
:root {
height: 100%;
font-family: 'DM Sans', Arial, Helvetica, sans-serif;
}
* {
font-family: inherit;
}
body {
margin: 0;
background-color: black;
display: grid;
place-items: center;
height: 100%;
}
</style>
<title>OpenGraph Debug Preview</title>
</head>` + (await inline(`<style>${styleNow}</style>${html}`))
)
return `<style>${styleNow}</style>${html}`
}

View file

@ -16,10 +16,10 @@
"author": "besties",
"license": "ISC",
"dependencies": {
"@besties/html2png": "^1.1.0",
"dotenv": "^16.3.1",
"eta": "^3.1.0",
"express": "^4.18.2",
"puppeteer": "^21.6.1",
"undici": "^5.24.0"
},
"type": "module",

982
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,10 @@
import 'dotenv/config'
import express from 'express'
import { Eta } from 'eta'
import render, { renderHtml } from './lib/render.js'
import render from './lib/render.js'
import languageColors from './lib/languagecolors.js'
import { fetch } from 'undici'
import hash from './lib/hash.js'
import { DMSans, ComicSans } from './lib/fonts.js'
// satori is using the native fetch api, causing a warning, so make node-fetch the default
globalThis.fetch = fetch
const forgejoBaseUrl = process.env.FORGEJO_BASE_URL
if (!forgejoBaseUrl) throw new Error('FORGEJO_BASE_URL unspecified')
@ -21,7 +18,7 @@ const eta = new Eta({
const app = express()
app.get('/', function (req, res) {
app.get('/', function (_, res) {
res.redirect('https://git.gay/gitgay/og.git')
})
@ -50,19 +47,19 @@ async function getLanguages(owner, repo) {
return {}
}
const comicSansNames = new Set(['trixie'])
const allowedFormats = new Set(['png', 'svg', 'json'])
app.use('/assets', express.static('assets'))
const defaultFormat = debug ? 'html' : 'png'
app.use('/', function (req, res, next) {
if (req.query.format && !allowedFormats.has(req.query.format)) {
res.status(400)
res.end()
return
app.locals.options = req.query.debug
? {
format: 'html'
}
app.locals.options = {
fonts: comicSansNames.has(req.params.owner) ? ComicSans : DMSans,
format: req.query.format ?? 'png'
: {
format: defaultFormat
}
res.type(app.locals.options.format)
next()
})
@ -87,15 +84,14 @@ app.get('/:user', async function (req, res) {
await reposResp.json()
])
user.repo_count = repos.length
user.description = user.description
?.split('---\r\n')
.slice(0, -1)
.join('---\r\n')
const html = await eta.renderAsync('user', {
user,
debug
})
if (debug) {
res.send(await renderHtml(html))
return
}
res.type(app.locals.options.format)
res.set('Content-Disposition', 'inline')
res.send(await render(html, app.locals.options))
})
@ -128,11 +124,6 @@ app.get('/:owner/:repo', async function (req, res) {
languageColors,
debug
})
if (debug) {
res.send(await renderHtml(html))
return
}
res.type(app.locals.options.format)
res.set('Content-Disposition', 'inline')
res.send(await render(html, app.locals.options))
})
@ -174,11 +165,6 @@ app.get('/:owner/:repo/commit/:hash', async function (req, res) {
languageColors,
debug
})
if (debug) {
res.send(await renderHtml(html))
return
}
res.type(app.locals.options.format)
res.set('Content-Disposition', 'inline')
res.send(await render(html, app.locals.options))
})
@ -219,11 +205,6 @@ app.get('/:owner/:repo/issues/:num', async function (req, res) {
languageColors,
debug
})
if (debug) {
res.send(await renderHtml(html))
return
}
res.type(app.locals.options.format)
res.set('Content-Disposition', 'inline')
res.send(await render(html, app.locals.options))
})
@ -270,11 +251,6 @@ app.get('/:owner/:repo/pulls/:num', async function (req, res) {
languageColors,
debug
})
if (debug) {
res.send(await renderHtml(html))
return
}
res.type(app.locals.options.format)
res.set('Content-Disposition', 'inline')
res.send(await render(html, app.locals.options))
})