serverside support for prngsentences
This commit is contained in:
parent
33fca057bc
commit
eb7770d5a9
4 changed files with 99 additions and 45 deletions
0
html/derivative.tsx
Normal file
0
html/derivative.tsx
Normal file
|
@ -1,2 +1,3 @@
|
||||||
// like crumbling but more complex and maybe cooler (ha) looking
|
// like crumbling but more complex and maybe cooler (ha) looking
|
||||||
// nah. too derivative
|
// nah. too derivative
|
||||||
|
// that gives me an idea
|
||||||
|
|
58
html/prngsentences.html
Normal file
58
html/prngsentences.html
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>PRNG sentences</title>
|
||||||
|
<meta itemprop="name" content="PRNG Sentences" />
|
||||||
|
<meta property="og:title" content="PRNG Sentences" />
|
||||||
|
<meta property="twitter:title" content="PRNG Sentences" />
|
||||||
|
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="helper for prng sentences made with prngnouns"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="helper for prng sentences made with prngnouns"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="twitter:description"
|
||||||
|
content="helper for prng sentences made with prngnouns"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="PRNG sentences" />
|
||||||
|
|
||||||
|
<meta name="theme-color" content="#eedd33" />
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--accent: #eedd33;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const render = text => {
|
||||||
|
return text;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onload = () => {
|
||||||
|
const words = document.getElementById("words");
|
||||||
|
const output = document.getElementById("output");
|
||||||
|
|
||||||
|
words.addEventListener(
|
||||||
|
"change",
|
||||||
|
() => (output.value = render(words.value))
|
||||||
|
);
|
||||||
|
|
||||||
|
words.addEventListener(
|
||||||
|
"keyup",
|
||||||
|
() => (output.value = render(words.value))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<textarea id="words"></textarea>
|
||||||
|
<textarea readonly id="output"></textarea>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -8,16 +8,17 @@ const font = await fetch("https://static.pyrope.net/courier-std-bold.otf")
|
||||||
.then((r) => r.arrayBuffer())
|
.then((r) => r.arrayBuffer())
|
||||||
.then((b) => new Uint8Array(b));
|
.then((b) => new Uint8Array(b));
|
||||||
|
|
||||||
// deciding now: pronouns (e.g. he/him) can be at most 32 chars
|
function make_image(
|
||||||
|
{ text, color = 0, outline_color = 0xff_ff_ff_ff }: {
|
||||||
let images: Map<string, { image: Uint8Array; fetched: number }> = new Map();
|
text: string;
|
||||||
|
color?: number;
|
||||||
function make_image(s: string): Image {
|
outline_color?: number;
|
||||||
console.log(`MAKING AN IMAGE FOR '${s}' (EXPENSIVE!)`);
|
},
|
||||||
|
): Image {
|
||||||
let image = Image.renderText(
|
let image = Image.renderText(
|
||||||
font,
|
font,
|
||||||
64,
|
64,
|
||||||
s,
|
text,
|
||||||
0,
|
0,
|
||||||
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
|
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
|
||||||
);
|
);
|
||||||
|
@ -25,8 +26,8 @@ function make_image(s: string): Image {
|
||||||
const outline = Image.renderText(
|
const outline = Image.renderText(
|
||||||
font,
|
font,
|
||||||
64,
|
64,
|
||||||
s,
|
text,
|
||||||
0xff_ff_ff_ff,
|
outline_color,
|
||||||
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
|
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -35,52 +36,30 @@ function make_image(s: string): Image {
|
||||||
image = image.composite(outline, hshift, vshift);
|
image = image.composite(outline, hshift, vshift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const text = Image.renderText(
|
const text_img = Image.renderText(
|
||||||
font,
|
font,
|
||||||
64,
|
64,
|
||||||
s,
|
text,
|
||||||
0x00_00_00_ff,
|
color,
|
||||||
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
|
new TextLayout({ verticalAlign: "center", horizontalAlign: "middle" }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const final = image.composite(text);
|
const final = image.composite(text_img);
|
||||||
return final.crop(0, 0, final.width, final.height - 22);
|
return final.crop(0, 0, final.width, final.height - 22);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function get_pronoun_image(prn: string): Promise<Uint8Array> {
|
|
||||||
if (images.has(prn)) {
|
|
||||||
const entry = images.get(prn)!;
|
|
||||||
entry.fetched++;
|
|
||||||
return entry.image;
|
|
||||||
}
|
|
||||||
const image = await make_image(prn).encode();
|
|
||||||
images.set(prn, { image, fetched: 1 });
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the whole cache thing def sketches me out, but people probably won't be *that* malicious
|
// the whole cache thing def sketches me out, but people probably won't be *that* malicious
|
||||||
const MAX_PRN_LENGTH = 128;
|
const MAX_PRN_LENGTH = 128;
|
||||||
const MAX_PRN_CACHE = 64;
|
|
||||||
// shouldn't really be a problem
|
// shouldn't really be a problem
|
||||||
const MAX_PRN_CHOICES = 256;
|
const MAX_PRN_CHOICES = 256;
|
||||||
|
|
||||||
function clean_up() {
|
// let's stick to hex even though BigInt() can handle prefixes (prefices?)
|
||||||
if (images.size <= MAX_PRN_CACHE) {
|
const hex_string_to_color = (s: string): number | undefined => {
|
||||||
console.log(
|
const parsed = parseInt(s, 16);
|
||||||
`not cleaning up, we only have ${images.size} cached which is less than ${MAX_PRN_CACHE}`,
|
if (Number.isNaN(parsed)) return;
|
||||||
);
|
// JANK! SORRY
|
||||||
return;
|
return Number((BigInt(parsed) << 8n) | 0xffn);
|
||||||
}
|
};
|
||||||
|
|
||||||
// reverse order!
|
|
||||||
const entries = [...images.entries()].toSorted(([_a, a], [_b, b]) =>
|
|
||||||
b.fetched - a.fetched
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log("before clean up:", images);
|
|
||||||
images = new Map(entries.slice(0, MAX_PRN_CACHE));
|
|
||||||
console.log("after clean up:", images);
|
|
||||||
}
|
|
||||||
|
|
||||||
const image_response = (data: Uint8Array): Response =>
|
const image_response = (data: Uint8Array): Response =>
|
||||||
new Response(data, {
|
new Response(data, {
|
||||||
|
@ -88,7 +67,9 @@ const image_response = (data: Uint8Array): Response =>
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.serve({ port: 61265 }, async (req) => {
|
Deno.serve({ port: 61265 }, async (req) => {
|
||||||
const prns = (new URL(req.url)).searchParams.getAll("p");
|
const url = new URL(req.url);
|
||||||
|
const params = url.searchParams;
|
||||||
|
const prns = params.getAll("p");
|
||||||
|
|
||||||
if (prns.some((p) => p.length > MAX_PRN_LENGTH)) {
|
if (prns.some((p) => p.length > MAX_PRN_LENGTH)) {
|
||||||
return new Response(`MAX_PRN_LENGTH = ${MAX_PRN_LENGTH}`, { status: 413 });
|
return new Response(`MAX_PRN_LENGTH = ${MAX_PRN_LENGTH}`, { status: 413 });
|
||||||
|
@ -103,7 +84,21 @@ Deno.serve({ port: 61265 }, async (req) => {
|
||||||
const prn = prns[Math.floor(Math.random() * prns.length)] ??
|
const prn = prns[Math.floor(Math.random() * prns.length)] ??
|
||||||
"NONE, APPARENTLY";
|
"NONE, APPARENTLY";
|
||||||
|
|
||||||
const resp = image_response(await get_pronoun_image(prn));
|
const fg_str = params.get("fg");
|
||||||
clean_up();
|
const outline_str = params.get("outline");
|
||||||
|
|
||||||
|
const sentence_id = params.get("sentence_id");
|
||||||
|
const sentence_index = params.get("sentence_index");
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${sentence_id}#${sentence_index}: chose ${prn} from ${prns}. ${fg_str} on ${outline_str}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const fg = hex_string_to_color(fg_str ?? "0");
|
||||||
|
const outline = hex_string_to_color(outline_str ?? "ffffff");
|
||||||
|
|
||||||
|
const resp = image_response(
|
||||||
|
await make_image({ text: prn, color: fg, outline_color: outline }).encode(),
|
||||||
|
);
|
||||||
return resp;
|
return resp;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue