cohost/serverside/this-image-has-been-fetched-approximately-n-times.ts
2024-02-24 20:40:21 -05:00

258 lines
11 KiB
TypeScript

import {
CanvasRenderingContext2D,
createCanvas,
} from "https://deno.land/x/canvas@v1.4.1/mod.ts";
// import { pick_random } from "./html/common.tsx";
import { randomInt } from "https://deno.land/std@0.146.0/node/internal/crypto/random.ts";
export const pick_random = <T>(xs: readonly T[]): T => xs[randomInt(xs.length)];
import { contentType } from "https://deno.land/std@0.202.0/media_types/mod.ts";
const canvas = createCanvas(413, 413);
const ctx = canvas.getContext("2d");
const default_fill = "#3B0920";
const bg_fill = "#FFE8D4";
const border_stroke = "#83254F";
ctx.fillStyle = "#FFE8D4";
ctx.strokeStyle = border_stroke;
ctx.lineWidth = 10;
ctx.fillRect(0, 0, 413, 413);
ctx.strokeRect(0, 0, 413, 413);
const fix_border = () => {
ctx.strokeStyle = border_stroke;
ctx.strokeRect(0, 0, 413, 413);
};
const clear_rect = (x: number, y: number, w: number, h: number) => {
ctx.strokeStyle = "";
ctx.fillStyle = bg_fill;
ctx.fillRect(x, y, w, h);
ctx.fillStyle = default_fill;
};
ctx.fillStyle = default_fill;
ctx.font = "bold 20px serif";
ctx.fillText("This image has been fetched about", 10, 130);
const funny_numbers = [69, 413, 420, 612, 6969, 8008, 8008135];
const scary_numbers = [666, 55555];
function draw_times(times: number) {
clear_rect(5, 150, 403, 125);
const num_digits = Math.floor(Math.log10(times)) + 1;
ctx.font = "bold 64px serif";
ctx.fillStyle = "#FFAB5C";
ctx.fillText(
`${times}`,
206.5 - (num_digits + 1) * 64 / 4,
216.5,
);
ctx.fillStyle = default_fill;
ctx.font = "bold 20px serif";
const times_bang = "times" + "!".repeat(num_digits - 1) +
(funny_numbers.includes(times) ? " (lol)" : "") +
(scary_numbers.includes(times) ? "(uh oh)" : "");
ctx.fillText(times_bang, 206.5 - (20 * (times_bang.length + 2)) / 4, 270);
}
const secret_messages = [
"hi",
"hhihihihihihihihii",
"what is your favorite post of mine?",
"how do you pronounce mehbark?",
"how many of these do you think there are?",
`i was instantiated at ${new Date().toISOString()}`,
"this isn't a very good numbers joke i'll be honest",
"i think these are fun. they're fun, right?",
"the idea of programmatic images used to be so cool and unreachable to me",
"i prefer having things getting really really squishy to inserting newlines or-- perish the thought-- *actually being smart* I LIED AND DID IT RIGHT",
"i should make most of these short though",
"eggbug BONUS SECRET MESSAGE: eggbug TWO (pronounced like peggle TWO)",
"this is literal cope but i love how messed up the text gets (old message, things are a bit better now)",
"i think i'll make one hundred",
"who is your favorite homestuck troll? (i have a favorite)",
"how do you feel about hiveswap?",
"would you kill me with a rock for one billion dollars?",
"would you kill me with a rock for *two* billion dollars?",
"would you kill me with a rock for one dollar?",
"Viral Math Problem: what is π",
"which member of the lambda cube is your favorite?",
"guess what band i'm listening to while writing this (there's literally no way for you to know)",
"how many of these secret messages have you seen before?",
"have you seen ME (the secret message) before???",
"there is a very small chance for the text above to say serket",
"there is an extremely small chance that the text above says serket RIGHT NOW",
"oh crap. this is only #27. why did i say i would make one hundred",
"i'm borrowing david mccullough's 1776 right now; it's really good so far",
"i am such a sucker for writing a bunch of messages that are randomly picked. i wrote a bunch for pyrope.net/falling when i wasn't doing great. they are so cringe yeesh",
"i love data-orientation so much it saves so much time",
"i have two keyboards on my desk but i mainly use the split one",
"if you see this, tell @cefqrn not to give up on ftct; they're so close!!",
"how many digits does the number above have?",
"have you figured out how the exclamation marks work? (it's a trivial pattern but annoying for people other than me to see)",
"randomness is so much easier when you can just Write Program Language",
"i am using Deno.serve for this (it works really well!)",
"okay, it's 10:15; i'm going to take a break and make this actually work",
"hooray, it's on pyrope.net/fetched.png now!",
`the "This post hasn't been deleted" post has the highest reach to effort ratio of any of my posts by far. it's pretty slick, don't get me wrong, but it was mainly just copying from cohost's css bla bla`,
"okay this is number 40 so i only have... oh boy",
"what is your favorite letter of your favorite alphabet?",
"internet was out for a bit, so i pulled up my youtube favorites from feb 2022, and apparently i had downloaded 42 HOURS of video",
'if you like discord servers created so that i could continue saying "man, computers are incredible" every day you should visit pyrope.net/mcai (ask me "approximately")',
"how do you feel about randall munroe?",
"can you screencap every message!?!?1",
"am i a choster yet?",
"is it a bad idea to have the majority of these random messages be inevitably lower quality?",
"there are some numbers that will get a (lol) after times, they are extremely rare though",
"you should read there is no antimemetics division by qntm",
"you should read valuable humans in transit and other stories by qntm",
"deno is great",
"deno emit seems sweet, but i couldn't find a simple cli (yes, any arbitrary script can become a single command easily because deno is awesome but)",
"godot is great; i actually make stuff instead of futzing with things that don't matter",
"go to pyrope.net/uhc",
"JSX is so conceptually perfect that it has totally ruined other html templating for me",
"drink water or something",
"FLKDHK: if you're reading this, go to pyrope.net/fetched.png and refresh until you see a message that starts with FLKDHK",
"have you seen this post? cohost.org/mehbark /post/2902858-this-post",
"you should go find the code together cohost.org/mehbark /post/2576955-find-the-code-togeth",
"you should play pyrope.net/ew it's genuinely fun",
"odds are you are just a computer program... actually the odds are 100% really because browser etc etc",
"is the number goku yet? will the number ever be goku? dm me on discord @mehbark if it is",
"irc.pyrope.net",
"thanks to the stackoverflow answer for the text wrapping; the text literally just got narrower to fit before",
"i don't use rust nearly as much as i used to, but i still like it a lot, and it might be the language i know best in many ways",
"shout out to purelymail! i've been using them for over a year and they're great (for terezi@pyrope.net of course)",
"i listened to in rainbows because r/topster said it was overrated or whatever, and now i think i just like radiohead",
"i like that cohost has official colors; it makes it easy to choose stuff that looks nice",
"eggbug is extremely valuable as a cultural touchstone for cohost, an otherwise fractured website, in this ess",
"i like rouge likes",
"played titanfall 2 multiplayer the other day (no northstar), and it just worked; i can't believe how back we are",
"i like 15 step",
'maybe "secret message" is overselling it',
"homestuck",
"i like all homestuck characters",
"what is your classpect?",
"what is your land?",
"how have you allocated your strife specibus?",
"abscond",
"i wonder how caching will affect this; i don't *think* i have any caching serverside",
"i am getting so close to one hundred now",
"on september 21, 2023, i belted a yoshi plushie to my knee",
"i have a $20 dollar digital casio watch from walmart; it is genuinely so perfect for me",
"it's 14:00 and i have only eaten one biscuit today",
"i like uhhhh dependent types",
"i found this at the bottom of the barrel",
"spogebob",
"it would be cool if floppies were actually reliable",
"epic win! this message has a 1% chance of appearing! share with your friends",
"you should try curling terezi.pyrope.net",
"Stubborn tiny lights vs. clustering darkness forever ok?",
// "caltrop.dev has a ton of cool stuff; the caltrop.dev/meta/map helps",
"i used a typescript type error to track my progress to one hundred messages",
"haskell...",
"lean4...",
"the amount of effort making all of these secret messages took was NOT worth the value added lol",
"because i did things in a weird way, if i don't clear some pixels they remain there until the program restarts",
"oh yeah i'm using deno.land/x/canvas and pretty happy with it; i used deno.land/x/skia_canvas, which is more fully-featured, before but there were some obnoxious glibc issues on my vps",
"why is it always the last few that take the longest",
"most of these are crappy secret messages. sorry",
"YOU FOUND MESSAGE #100 LET'S GOOOOOO",
] as const;
type completed = typeof secret_messages.length;
const _done: completed = 100;
// thank you, https://stackoverflow.com/questions/5026961/html5-canvas-ctx-filltext-wont-do-line-breaks
function printAtWordWrap(
context: CanvasRenderingContext2D,
text: string,
x: number,
y: number,
lineHeight: number,
fitWidth: number,
) {
fitWidth = fitWidth || 0;
if (fitWidth <= 0) {
context.fillText(text, x, y);
return;
}
let words = text.split(" ");
let currentLine = 0;
let idx = 1;
while (words.length > 0 && idx <= words.length) {
const str = words.slice(0, idx).join(" ");
const w = context.measureText(str).width;
if (w > fitWidth) {
if (idx == 1) {
idx = 2;
}
context.fillText(
words.slice(0, idx - 1).join(" "),
x,
y + (lineHeight * currentLine),
);
currentLine++;
words = words.splice(idx - 1);
idx = 1;
} else {
idx++;
}
}
if (idx > 0) {
context.fillText(words.join(" ") + " ", x, y + (lineHeight * currentLine));
}
}
function draw_secret_message(message?: string) {
clear_rect(5, 288, 403, 120);
ctx.font = "14px serif";
ctx.fillText(
`your ${Math.random() > 0.99 ? "serket" : "secret"} message is:`,
115,
300,
);
const msg = message ?? pick_random(secret_messages);
printAtWordWrap(ctx, msg, 10, 325, 18, 395);
// ctx.fillText(, 10, 340, 395);
}
const kv = await Deno.openKv();
Deno.args.includes("--reset-count") && await kv.set(["fetched"], 0);
async function num_requests(): Promise<number> {
const got = (await kv.get(["fetched"])).value;
if (typeof got == "number") {
return got;
}
return 0;
}
async function count_request() {
await kv.set(["fetched"], await num_requests() + 1);
}
Deno.serve({ port: 61261 }, async () => {
await count_request();
const num = await num_requests();
draw_times(num);
const msg = pick_random(secret_messages);
draw_secret_message(msg);
console.log(`${num}: ${msg}`);
fix_border();
const image_format = "png";
return new Response(canvas.toBuffer(), {
headers: { "Content-Type": contentType(image_format) },
});
});