import { DidResolver } from "@atproto/identity"; import { iterateAtpRepo } from "@atcute/car"; import { appendFileSync, unlinkSync } from "node:fs"; const didres = new DidResolver({}); async function getPds(did) { var doc = await didres.resolve(did); var {serviceEndpoint} = doc.service.find(s => s.id == "#atproto_pds"); return serviceEndpoint; } async function getRepo(pds, did) { console.log("getRepo", pds, did); var res = await fetch(`${pds}/xrpc/com.atproto.sync.getRepo?did=${did}`); if (!res.ok) throw new Error(`${res.status} ${await res.text()}`); var ab = await res.arrayBuffer(); var u = new Uint8Array(ab); return u; } async function getFollowing(repo) { var following = []; for (var { collection, rkey, record } of iterateAtpRepo(repo)) { if (collection == "app.bsky.graph.follow") { following.push(record.subject); } } return following; } async function getMediaPosts(repo, did) { var posts = []; for (var { collection, rkey, record } of iterateAtpRepo(repo)) { if (collection == "app.bsky.feed.post" && ["app.bsky.embed.images", "app.bsky.embed.video"].includes(record.embed?.$type)) { posts.push(`at://${did}/app.bsky.feed.post/${rkey}`); } } return posts; } var did = "did:plc:u4gngygg2w5egsigxu5g7byu"; var pds = await getPds(did); var repo = await getRepo(pds, did); var following = await getFollowing(repo); unlinkSync("posts.txt"); var failed = []; for (let did of following) { console.log(`${following.indexOf(did)} / ${following.length}`); try { let pds = await getPds(did); let repo = await getRepo(pds, did); let posts = await getMediaPosts(repo, did); appendFileSync("posts.txt", posts.join("\n") + "\n"); } catch (error) { console.error(error); failed.push(did); } } if (failed.length) console.log(`${failed.length} dids failed: `, failed.join(', '));