Monorepo for Aesthetic.Computer aesthetic.computer
at main 117 lines 3.9 kB view raw
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};