the home site for me: also iteration 3 or 4 of my site
1import puppeteer from "puppeteer";
2import { readdir, mkdir } from "node:fs/promises";
3
4const template = await Bun.file("tools/og.html").text();
5
6const browser = await puppeteer.launch({
7 args: ["--no-sandbox"],
8 executablePath: process.env.PUPPETEER_EXEC_PATH, // set by docker container
9});
10
11async function og(
12 postname: string,
13 type: string,
14 by: string | undefined,
15 outputPath: string,
16 width = 1200,
17 height = 630,
18) {
19 const page = await browser.newPage();
20
21 await page.setViewport({ width, height });
22
23 await page.setContent(
24 template
25 .toString()
26 .replace("{{postname}}", postname)
27 .replace("{{type}}", type)
28 .replace("{{by}}", by || ""),
29 );
30
31 await page.screenshot({ path: outputPath });
32}
33
34async function fileExists(path: string): Promise<boolean> {
35 try {
36 await Bun.file(path);
37 return true;
38 } catch (e) {
39 return false;
40 }
41}
42
43try {
44 // check if the public/blog folder exists
45 // if not exit
46 // if it does, get all the folders and then get the title tag from the index.html
47
48 if (!(await fileExists("public/"))) {
49 console.error("public/ does not exist");
50 process.exit(1);
51 }
52
53 // read all the files in the current directory filtering for index.htmls
54 const files = (await readdir("public/", { recursive: true })).filter((file) =>
55 file.endsWith("index.html"),
56 );
57
58 const directories = new Set(
59 files.map((file) => file.replace("index.html", "")),
60 );
61
62 const existing = (await readdir("static/")).filter((file) =>
63 directories.has(file),
64 );
65
66 // create not existing
67 for (const dir of directories) {
68 if (!existing.includes(dir)) {
69 await mkdir(`static/${dir.split("/").slice(0, -1).join("/")}`, {
70 recursive: true,
71 });
72 }
73 }
74
75 console.log("Generating OG images for", files.length, "files");
76
77 // for each file, get the title tag from the index.html
78 for (const file of files) {
79 const index = await Bun.file(`public/${file}`).text();
80 const title = index.match(/<title>(.*?)<\/title>/)[1];
81 let type = "Page";
82 let by: string | undefined;
83 switch (file.split("/")[0]) {
84 case "blog":
85 type = "Blog";
86 if (file.split("/")[1] !== "index.html") {
87 by = "<p>A post ... yeah thats about it</p>";
88 } else {
89 by = "<p>All authored by me ... or are they???</p>";
90 }
91 break;
92 case "verify":
93 type = "Slash Page";
94 by = "<p>So you can stalk me 💀</p>";
95 break;
96 case "pfp":
97 type = "Slash Page";
98 by = "<p>Want to stare at my pretty face?</p>";
99 break;
100 case "tags":
101 if (file.split("/")[1] === "index.html") {
102 type = "Tags";
103 by = "<p>A total archive!</p>";
104 } else {
105 type = "Tag";
106 by = "<p>Find more posts like this!</p>";
107 }
108 break;
109 case "index.html":
110 type = "Root";
111 by = "<p>Where it all begins</p>";
112 break;
113 }
114
115 console.log("Generating OG for", file, "title:", title, "with type:", type);
116 await og(title, type, by, `static/${file.replace("index.html", "og.png")}`);
117 }
118} catch (e) {
119 console.error(e);
120} finally {
121 await browser.close();
122}