From 8aad4c6d4552174a7f92a628c071702ef041e23f Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Sun, 27 Jul 2025 17:20:10 +0000 Subject: [PATCH] avatar: generate a random color for users without a pfp Signed-off-by: Anirudh Oppiliappan --- avatar/src/index.js | 37 +++++++++++++++++++++++++++++++++---- 1 file(s) changed, 33 insertion(s)(+), 4 deletion(s)(-) diff --git a/avatar/src/index.js b/avatar/src/index.js --- a/avatar/src/index.js +++ b/avatar/src/index.js @@ -1,5 +1,19 @@ export default { async fetch(request, env) { + // Helper function to generate a color from a string + const stringToColor = (str) => { + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + let color = "#"; + for (let i = 0; i < 3; i++) { + const value = (hash >> (i * 8)) & 0xff; + color += ("00" + value.toString(16)).substr(-2); + } + return color; + }; + const url = new URL(request.url); const { pathname, searchParams } = url; @@ -60,14 +74,29 @@ ); const profile = await profileResponse.json(); const avatar = profile.avatar; - if (!avatar) { - return new Response(`avatar not found for ${actor}.`, { status: 404 }); + let avatarUrl = profile.avatar; + + if (!avatarUrl) { + // Generate a random color based on the actor string + const bgColor = stringToColor(actor); + const size = resizeToTiny ? 32 : 128; + const svg = ``; + const svgData = new TextEncoder().encode(svg); + + response = new Response(svgData, { + headers: { + "Content-Type": "image/svg+xml", + "Cache-Control": "public, max-age=43200", + }, + }); + await cache.put(cacheKey, response.clone()); + return response; } // Resize if requested let avatarResponse; if (resizeToTiny) { - avatarResponse = await fetch(avatar, { + avatarResponse = await fetch(avatarUrl, { cf: { image: { width: 32, @@ -78,7 +107,7 @@ }, }, }); } else { - avatarResponse = await fetch(avatar); + avatarResponse = await fetch(avatarUrl); } if (!avatarResponse.ok) { -- tangled.sh