avatar: fetch tangled avatar before falling back to bsky & random color #893

open
opened by anirudh.fi targeting master from icy/tolqpt
Changed files
+31 -6
avatar
src
+31 -6
avatar/src/index.js
··· 23 } 24 25 const size = searchParams.get("size"); 26 const resizeToTiny = size === "tiny"; 27 28 const cache = caches.default; ··· 56 message: "avatar request for: " + actor, 57 computedSignature: computedSig, 58 providedSignature: signatureHex, 59 }); 60 61 const sigBytes = Uint8Array.from( ··· 68 } 69 70 try { 71 - const profileResponse = await fetch( 72 - `https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${actor}`, 73 - ); 74 - const profile = await profileResponse.json(); 75 - const avatar = profile.avatar; 76 77 - let avatarUrl = profile.avatar; 78 79 if (!avatarUrl) { 80 // Generate a random color based on the actor string
··· 23 } 24 25 const size = searchParams.get("size"); 26 + const blobUrl = searchParams.get("blob"); // URL to fetch Tangled avatar from PDS 27 const resizeToTiny = size === "tiny"; 28 29 const cache = caches.default; ··· 57 message: "avatar request for: " + actor, 58 computedSignature: computedSig, 59 providedSignature: signatureHex, 60 + hasBlobUrl: !!blobUrl, 61 }); 62 63 const sigBytes = Uint8Array.from( ··· 70 } 71 72 try { 73 + let avatarUrl = null; 74 + 75 + // If blob URL is provided, use it (Tangled profile avatar from user's PDS) 76 + if (blobUrl) { 77 + try { 78 + const decodedBlobUrl = decodeURIComponent(blobUrl); 79 + console.log({ 80 + level: "debug", 81 + message: "fetching Tangled avatar from PDS", 82 + actor: actor, 83 + blobUrl: decodedBlobUrl, 84 + }); 85 + avatarUrl = decodedBlobUrl; 86 + } catch (e) { 87 + console.log({ 88 + level: "warn", 89 + message: "failed to decode blob URL, falling back to Bluesky", 90 + error: e.message, 91 + }); 92 + } 93 + } 94 95 + // If no blob URL or it failed, fall back to Bluesky 96 + if (!avatarUrl) { 97 + const profileResponse = await fetch( 98 + `https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${actor}`, 99 + ); 100 + const profile = await profileResponse.json(); 101 + avatarUrl = profile.avatar; 102 + } 103 104 if (!avatarUrl) { 105 // Generate a random color based on the actor string