Monorepo for Aesthetic.Computer
aesthetic.computer
1// Logo, 23.05.02.22.09
2// Proxy a random logo from one endpoint.
3// If loaded in the browser, return a tappable HTML response to cycle logos.
4// Otherwise, proxy the `.png`.
5
6/* #region 🏁 TODO
7 - [] Make it cooler?
8#endregion */
9
10import { respond } from "../../backend/http.mjs";
11import { logoUrl } from "../../backend/logo.mjs";
12
13export async function handler(event, context) {
14 // Make sure this is a GET request
15 if (event.httpMethod !== "GET") {
16 return respond(405, { error: "Wrong request type." });
17 }
18
19 const { got } = await import("got");
20
21 const queryParams = new URLSearchParams(event.queryStringParameters);
22 const previousLogo = queryParams.get("previousLogo");
23
24 let logo;
25 do {
26 logo = logoUrl();
27 } while (logo === previousLogo); // Make sure we don't select the same logo
28
29 const response = await got(logo, {
30 responseType: "buffer",
31 https: { rejectUnauthorized: false },
32 });
33
34 const base64Logo = Buffer.from(response.body, "binary").toString("base64");
35
36 const userAgent = event.headers["user-agent"] || "";
37 const isServer =
38 userAgent.includes("curl") ||
39 userAgent.includes("wget") ||
40 userAgent.includes("python-requests") ||
41 userAgent.includes("node-fetch");
42 const isPngEndpoint = event.path.split("/").pop() === "logo.png";
43 // Return raw PNG when embedded via <img> tags (Accept header prefers images)
44 const accept = event.headers["accept"] || "";
45 const wantsImage = accept.startsWith("image/") || (accept.includes("image/*") && !accept.includes("text/html"));
46
47 if (isServer || isPngEndpoint || wantsImage) {
48 return {
49 statusCode: 200,
50 headers: {
51 "Content-Type": "image/png",
52 "Access-Control-Allow-Origin": "*",
53 "Cache-Control": "no-cache",
54 },
55 body: base64Logo,
56 isBase64Encoded: true,
57 };
58 } else {
59 const htmlResponse = `
60 <html>
61 <head>
62 <link rel="icon" href="${logo}" type="image/x-icon">
63 <style>
64 html { height: 100%; }
65 body {
66 display: flex;
67 justify-content: center;
68 align-items: center;
69 height: 100%;
70 background-color: ${randomPurple()};
71 margin: 0;
72 overflow: hidden;
73 transition: filter 0.2s;
74 }
75 body.blurred {
76 filter: blur(5px);
77 }
78 img {
79 object-fit: contain;
80 width: 100vw;
81 height: 100%;
82 cursor: pointer;
83 }
84 </style>
85 </head>
86 <body>
87 <img crossorigin src="${logo}" onclick="updateQueryString()">
88 </body>
89 <script>
90 const strippedUrl = window.location.origin + window.location.pathname;
91 window.history.replaceState({}, document.title, strippedUrl);
92 function updateQueryString() {
93 document.body.classList.add('blurred');
94 const currentLogoId = '${logo}';
95 const newURL = strippedUrl + '?previousLogo=' + encodeURIComponent(currentLogoId);
96 setTimeout(() => { window.location = newURL; }, 200);
97 }
98 </script>
99 </html>
100`;
101
102 return {
103 statusCode: 200,
104 headers: {
105 "Content-Type": "text/html",
106 },
107 body: htmlResponse,
108 };
109 }
110}
111
112const randomPurple = () => {
113 const r = Math.floor(Math.random() * 50 + 50); // Values between 200 and 255
114 const g = Math.floor(Math.random() * 25); // Values between 0 and 50
115 const b = Math.floor(Math.random() * 50 + 50); // Values between 200 and 255
116 return `rgb(${r},${g},${b})`;
117};