From c7613c4c093e6fa8e704f81ffefb39e9deb873f3 Mon Sep 17 00:00:00 2001 From: "planetrenox@protonmail.com" Date: Mon, 26 Oct 2026 17:48:50 +0000 Subject: [PATCH] Feat: Link the deploy report's top images to the run summary, with a button for the run Also drops the Pages fallback notes, since the Pages project is gone. Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- scripts/notify.js | 20 ++++++++++++++------ scripts/promote.js | 2 +- wrangler.jsonc | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index adb12ae..dfc5d13 100644 --- a/README.md +++ b/README.md @@ -268,7 +268,7 @@ Fork this repo and add these **GitHub Actions secrets** (Settings → Secrets an ### 9. Domains and Rules -Change the three `routes` in `wrangler.jsonc` to your domain, `free.` and `ai.` (each needs a proxied DNS record). Any hostname starting with `free.` serves free images, and any starting with `ai.` serves AI images; everything else serves regular search. +Change the three `routes` in `wrangler.jsonc` to your domain, `free.` and `ai.` (each needs a proxied DNS record; with nothing behind it, use `AAAA 100::`). Any hostname starting with `free.` serves free images, and any starting with `ai.` serves AI images; everything else serves regular search. Then add the rules that let static images work (needs a token with Zone: Transform Rules Edit and Single Redirect Edit): diff --git a/scripts/notify.js b/scripts/notify.js index 171b3d9..bf783a3 100644 --- a/scripts/notify.js +++ b/scripts/notify.js @@ -1,6 +1,6 @@ // Sends the deploy's outcome to ntfy: what got promoted, how close the account is to the free plan's limits, and what // to do when something needs attention. Runs last in .github/workflows/deploy.yml, even when an earlier step failed. -import { readFile } from "node:fs/promises"; +import { readFile, appendFile } from "node:fs/promises"; const env = process.env; const r = JSON.parse(await readFile("promoted/report.json", "utf8").catch(() => "{}")); @@ -30,15 +30,23 @@ if (r.workers) { if (total >= 8e4) actions.push(`Worker requests hit ${pct(total, 1e5)} of the free 100,000/day; past it, images that aren't static files break until 00:00 UTC. Lower \`MIN_VIEWS\` to promote more, or move to Workers Paid ($5/mo).`); } if (r.workersError) lines.push(`**Worker requests:** couldn't read (${esc(r.workersError)})`); -// web/1/orange+cat → orange cat, free/2/orange+cat → orange cat i=2 (free) -const label = id => esc(id.replace(/^(\w+)\/(\d+)\/(.*)$/, (_, f, i, q) => `${q.replaceAll("+", " ")}${i > 1 ? ` i=${i}` : ""}${f !== "web" ? ` (${f})` : ""}`)); + +// The top images, with thumbnails, go on the run's summary page, which the message links to. free/2/orange+cat → +// https://free.direct-img.link/orange+cat?i=2 (a static file, so viewing the page doesn't cost Worker requests). +if (r.top?.length && env.GITHUB_STEP_SUMMARY) { + const zone = env.ZONE || "direct-img.link"; + const rows = r.top.map(({ id, views }) => { + const [f, i, name] = id.split("/"), url = `https://${f === "web" ? "" : `${f}.`}${zone}/${name}${i > 1 ? `?i=${i}` : ""}`; + return `| | [${esc(name.replaceAll("+", " "))}](${url}) | ${f === "web" ? "main" : f} | ${i} | ${fmt(views)} |`; + }); + await appendFile(env.GITHUB_STEP_SUMMARY, `## Top static images (views in the last ${r.days} days)\n\n| | Query | Site | i | Views |\n|---|---|---|---|---|\n${rows.join("\n")}\n`); +} const failed = env.STATUS !== "success"; const body = [ lines.join(" \n"), - r.top?.length && `**Top images**\n${r.top.map((t, n) => `${n + 1}. ${label(t.id)} — ${fmt(t.views)}`).join("\n")}`, + r.top?.length && env.RUN_URL && `[See top images](${env.RUN_URL})`, actions.length && `**⚠ Needs attention**\n${actions.map(a => `- ${a}`).join("\n")}`, - env.RUN_URL && `[Open the run](${env.RUN_URL})`, ].filter(Boolean).join("\n\n") || "No report was written."; console.log(body); if (!env.NTFY_URL) process.exit(0); @@ -50,7 +58,7 @@ const res = await fetch(env.NTFY_URL.startsWith("http") ? env.NTFY_URL : `https: Priority: failed ? "5" : actions.length ? "4" : "2", Tags: failed ? "rotating_light,x" : actions.length ? "warning" : "white_check_mark", Markdown: "yes", - ...(env.RUN_URL && { Click: env.RUN_URL }), + ...(env.RUN_URL && { Actions: `view, Open run, ${env.RUN_URL}` }), ...(env.NTFY_TOKEN && { Authorization: `Bearer ${env.NTFY_TOKEN}` }), }, }); diff --git a/scripts/promote.js b/scripts/promote.js index 0223520..72528d7 100644 --- a/scripts/promote.js +++ b/scripts/promote.js @@ -167,7 +167,7 @@ Object.assign(report, { ok: true, promoted: ids.length, bytes, added: ids.filter(id => !prev[id]).length, removed: Object.keys(prev).filter(id => !chosen[id]).length, promotedViews: ids.reduce((a, id) => a + chosen[id].views, 0), - top: ids.slice(0, 5).map(id => ({ id, views: chosen[id].views })), + top: ids.slice(0, 50).map(id => ({ id, views: chosen[id].views })), }); await writeFile(`${CACHE}/report.json`, JSON.stringify(report, null, 2)); console.log(JSON.stringify(report, null, 2)); diff --git a/wrangler.jsonc b/wrangler.jsonc index 2c7019f..a236af5 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -9,7 +9,7 @@ "r2_buckets": [{ "binding": "R2_IMAGES", "bucket_name": "direct-img-store" }], "kv_namespaces": [{ "binding": "DIRECT_IMG_CACHE", "id": "3d7301ab34db464cb568f31cbea7ce8c" }], "vars": { "GOATCOUNTER_URL": "https://direct-img.goatcounter.com" }, - // Routes rather than custom domains, so the old Pages project stays behind them as the origin to roll back to + // Each hostname has a proxied placeholder DNS record (AAAA 100::), since the worker answers everything itself "routes": [ { "pattern": "direct-img.link/*", "zone_name": "direct-img.link" }, { "pattern": "free.direct-img.link/*", "zone_name": "direct-img.link" },