your personal website on atproto - mirror blento.app
at fix-cached-posts 78 lines 2.4 kB view raw
1import { getRecord, listRecords, parseUri, resolveHandle } from '$lib/atproto'; 2import type { Did, Handle } from '@atcute/lexicons'; 3import { isDid } from '@atcute/lexicons/syntax'; 4 5interface GalleryItem { 6 value: { 7 gallery: string; 8 item: string; 9 position?: number; 10 }; 11} 12 13// Parse grain.social gallery URLs 14// https://grain.social/profile/atproto.boston/gallery/3megtiuwqs62w 15export function parseGrainGalleryUrl(url: string): { handle: string; rkey: string } | null { 16 const match = url.match(/grain\.social\/profile\/([^/]+)\/gallery\/([A-Za-z0-9]+)/); 17 if (!match) return null; 18 return { handle: match[1], rkey: match[2] }; 19} 20 21export async function loadGrainGalleryData(items: { cardData: Record<string, unknown> }[]) { 22 const itemsData: Record<string, unknown[]> = {}; 23 24 const galleryItems: Record<string, GalleryItem[] | undefined> = { 25 'social.grain.gallery.item': undefined 26 }; 27 28 for (const item of items) { 29 if (!item.cardData.galleryUri) continue; 30 31 const galleryUri = item.cardData.galleryUri as string; 32 const parsedUri = parseUri(galleryUri); 33 34 if (parsedUri?.collection === 'social.grain.gallery') { 35 let repo = parsedUri.repo; 36 37 // Resolve handle to DID if needed 38 if (!isDid(repo)) { 39 const did = await resolveHandle({ handle: repo as Handle }); 40 if (!did) continue; 41 repo = did; 42 } 43 44 // Construct DID-based URI for filtering (PDS records use DID-based URIs) 45 const didBasedGalleryUri = `at://${repo}/social.grain.gallery/${parsedUri.rkey}`; 46 47 const itemCollection = 'social.grain.gallery.item'; 48 49 if (!galleryItems[itemCollection]) { 50 galleryItems[itemCollection] = (await listRecords({ 51 did: repo as Did, 52 collection: itemCollection 53 })) as unknown as GalleryItem[]; 54 } 55 56 const galleryItemsList = galleryItems['social.grain.gallery.item']; 57 if (!galleryItemsList) continue; 58 59 const images = galleryItemsList 60 .filter((i) => i.value.gallery === didBasedGalleryUri) 61 .map(async (i) => { 62 const itemData = parseUri(i.value.item); 63 if (!itemData) return null; 64 const record = await getRecord({ 65 did: itemData.repo as Did, 66 collection: itemData.collection!, 67 rkey: itemData.rkey 68 }); 69 return { ...record, value: { ...record.value, ...i.value } }; 70 }); 71 72 // Store under original key so the component can look it up 73 itemsData[galleryUri] = await Promise.all(images); 74 } 75 } 76 77 return itemsData; 78}