+33
-4
avatar/src/index.js
+33
-4
avatar/src/index.js
···
1
1
export default {
2
2
async fetch(request, env) {
3
+
// Helper function to generate a color from a string
4
+
const stringToColor = (str) => {
5
+
let hash = 0;
6
+
for (let i = 0; i < str.length; i++) {
7
+
hash = str.charCodeAt(i) + ((hash << 5) - hash);
8
+
}
9
+
let color = "#";
10
+
for (let i = 0; i < 3; i++) {
11
+
const value = (hash >> (i * 8)) & 0xff;
12
+
color += ("00" + value.toString(16)).substr(-2);
13
+
}
14
+
return color;
15
+
};
16
+
3
17
const url = new URL(request.url);
4
18
const { pathname, searchParams } = url;
5
19
···
60
74
const profile = await profileResponse.json();
61
75
const avatar = profile.avatar;
62
76
63
-
if (!avatar) {
64
-
return new Response(`avatar not found for ${actor}.`, { status: 404 });
77
+
let avatarUrl = profile.avatar;
78
+
79
+
if (!avatarUrl) {
80
+
// Generate a random color based on the actor string
81
+
const bgColor = stringToColor(actor);
82
+
const size = resizeToTiny ? 32 : 128;
83
+
const svg = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}" xmlns="http://www.w3.org/2000/svg"><rect width="${size}" height="${size}" fill="${bgColor}"/></svg>`;
84
+
const svgData = new TextEncoder().encode(svg);
85
+
86
+
response = new Response(svgData, {
87
+
headers: {
88
+
"Content-Type": "image/svg+xml",
89
+
"Cache-Control": "public, max-age=43200",
90
+
},
91
+
});
92
+
await cache.put(cacheKey, response.clone());
93
+
return response;
65
94
}
66
95
67
96
// Resize if requested
68
97
let avatarResponse;
69
98
if (resizeToTiny) {
70
-
avatarResponse = await fetch(avatar, {
99
+
avatarResponse = await fetch(avatarUrl, {
71
100
cf: {
72
101
image: {
73
102
width: 32,
···
78
107
},
79
108
});
80
109
} else {
81
-
avatarResponse = await fetch(avatar);
110
+
avatarResponse = await fetch(avatarUrl);
82
111
}
83
112
84
113
if (!avatarResponse.ok) {