powerpointproto slides.waow.tech
slides

fix: resolve PDS URLs for public gallery thumbnails

+37 -37
+37 -37
src/routes/+page.svelte
··· 3 3 import { goto } from "$app/navigation"; 4 4 import { editorState, newDeck, loadDeck, startPresenting } from "$lib/state.svelte"; 5 5 import { auth, initAuth, doDeleteDeck } from "$lib/auth.svelte"; 6 - import { getDeck, getBlobUrl, type Deck } from "$lib/api"; 6 + import { getDeck, getBlobUrl, resolvePdsUrl, type Deck } from "$lib/api"; 7 7 import Toolbar from "$lib/components/Toolbar.svelte"; 8 8 import SlideList from "$lib/components/SlideList.svelte"; 9 9 import SlideCanvas from "$lib/components/SlideCanvas.svelte"; ··· 29 29 if (!res.ok) return; 30 30 const records = await res.json(); 31 31 32 - // Map to our format 33 - const decks: PublicDeck[] = records.map((r: { 32 + // Get unique DIDs and resolve their PDS URLs + handles in parallel 33 + type RecordType = { 34 34 did: string; 35 35 rkey: string; 36 36 record: { ··· 38 38 slides: unknown[]; 39 39 thumbnail?: { ref: { $link: string }; mimeType: string }; 40 40 }; 41 - }) => ({ 41 + }; 42 + const dids = [...new Set(records.map((r: RecordType) => r.did))]; 43 + const pdsMap = new Map<string, string>(); 44 + const handleMap = new Map<string, string>(); 45 + 46 + await Promise.all([ 47 + // Resolve PDS URLs 48 + ...dids.map(async (did) => { 49 + try { 50 + const pdsUrl = await resolvePdsUrl(did); 51 + pdsMap.set(did, pdsUrl); 52 + } catch {} 53 + }), 54 + // Resolve handles via getProfiles 55 + (async () => { 56 + if (dids.length > 0) { 57 + try { 58 + const params = dids.map((d: string) => `actors=${d}`).join("&"); 59 + const res = await fetch(`https://public.api.bsky.app/xrpc/app.bsky.actor.getProfiles?${params}`); 60 + if (res.ok) { 61 + const data = await res.json(); 62 + for (const profile of data.profiles || []) { 63 + handleMap.set(profile.did, profile.handle); 64 + } 65 + } 66 + } catch {} 67 + } 68 + })(), 69 + ]); 70 + 71 + // Map to our format with resolved PDS URLs 72 + const decks: PublicDeck[] = records.map((r: RecordType) => ({ 42 73 did: r.did, 43 74 rkey: r.rkey, 44 75 name: r.record.name || "untitled", 45 76 slideCount: r.record.slides?.length || 0, 46 77 thumbnailUrl: r.record.thumbnail 47 - ? getBlobUrl(r.did, r.record.thumbnail.ref.$link) 78 + ? getBlobUrl(r.did, r.record.thumbnail.ref.$link, pdsMap.get(r.did)) 48 79 : undefined, 80 + handle: handleMap.get(r.did), 49 81 })); 50 - 51 - // Resolve handles in parallel 52 - const dids = [...new Set(decks.map(d => d.did))]; 53 - const handleMap = new Map<string, string>(); 54 - 55 - await Promise.all(dids.map(async (did) => { 56 - try { 57 - const res = await fetch(`https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle?did=${did}`); 58 - if (res.ok) { 59 - // This endpoint doesn't exist, use getProfile instead 60 - } 61 - } catch {} 62 - })); 63 - 64 - // Use getProfiles to batch resolve 65 - if (dids.length > 0) { 66 - try { 67 - const params = dids.map(d => `actors=${d}`).join("&"); 68 - const res = await fetch(`https://public.api.bsky.app/xrpc/app.bsky.actor.getProfiles?${params}`); 69 - if (res.ok) { 70 - const data = await res.json(); 71 - for (const profile of data.profiles || []) { 72 - handleMap.set(profile.did, profile.handle); 73 - } 74 - } 75 - } catch {} 76 - } 77 - 78 - // Apply handles 79 - for (const deck of decks) { 80 - deck.handle = handleMap.get(deck.did); 81 - } 82 82 83 83 publicDecks = decks; 84 84 } catch (e) {