ninelands-reddit/scripts/capture/community.mjs
Lukas Müllner 099f884dcb feat: Bilder und Texte für die Community-Posts in r/Ninelands
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 21:41:46 +01:00

91 lines
2.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
// Bilder für die Community-Posts in r/Ninelands (1080 × 1350, hochkant für den Feed am Handy).
// Aufruf: npm run capture:community → dist/marketing/community/how-to-play.png, realms.png
import {copyFileSync, mkdirSync, readFileSync, statSync} from 'node:fs'
import {createServer} from 'node:http'
import {dirname, extname, join, resolve} from 'node:path'
import {fileURLToPath} from 'node:url'
import {build} from 'esbuild'
import {chromium} from 'playwright'
const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..')
const site = join(root, 'dist/community')
const out = join(root, 'dist/marketing/community')
mkdirSync(site, {recursive: true})
mkdirSync(out, {recursive: true})
await build({
entryPoints: [join(root, 'scripts/capture/community.ts')],
bundle: true,
format: 'esm',
outdir: site,
logLevel: 'warning',
define: {
'import.meta.env.MODE': '"reddit"',
'import.meta.env.BASE_URL': '"/"',
__API_ORIGIN__: '""',
},
loader: {'.woff2': 'file', '.woff': 'file'},
assetNames: 'fonts/[name]-[hash]',
})
copyFileSync(
join(root, 'scripts/capture/community.html'),
join(site, 'index.html'),
)
const types = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.png': 'image/png',
'.woff2': 'font/woff2',
'.woff': 'font/woff',
}
const server = createServer((req, res) => {
const path = decodeURIComponent((req.url ?? '/').split('?')[0])
for (const dir of [site, join(root, 'public')]) {
const file = join(dir, path === '/' ? 'index.html' : path)
try {
if (file.startsWith(dir) && statSync(file).isFile()) {
res.writeHead(200, {
'Content-Type': types[extname(file)] ?? 'application/octet-stream',
})
res.end(readFileSync(file))
return
}
} catch {}
}
res.writeHead(404)
res.end()
})
await new Promise(r => server.listen(0, '127.0.0.1', r))
const base = `http://127.0.0.1:${server.address().port}/`
const browser = await chromium.launch()
try {
for (const page of ['howto', 'realms']) {
const p = await browser.newPage({
viewport: {width: 540, height: 675},
deviceScaleFactor: 2,
})
p.on('pageerror', e => console.error(`Seitenfehler: ${e.message}`))
await p.goto(`${base}?page=${page}`)
await p.evaluate(() => document.fonts.ready)
await p.waitForLoadState('networkidle')
// Passt alles aufs Bild?
const over = await p.evaluate(() => {
const s = document.getElementById('sheet')
return s ? s.scrollHeight - s.clientHeight : 0
})
if (over > 0) console.error(`${page}: ${over} px zu hoch`)
const name = page === 'howto' ? 'how-to-play.png' : 'realms.png'
await p.screenshot({path: join(out, name)})
console.log(
`${name} ${Math.round(statSync(join(out, name)).size / 1024)} KB`,
)
await p.close()
}
} finally {
await browser.close()
server.close()
}