bsky follow audit script
1import { IDENTIFIER, MONTHS_IN_DAYS } from "./constants";
2import {
3 getDateDifferenceInDays,
4 getFollowRecords,
5 getRecentPost,
6 resolveIdentity,
7} from "./utils";
8
9let cursor: string | undefined;
10
11const unfollows = [];
12
13const doc = await resolveIdentity(IDENTIFIER);
14
15do {
16 const { follows, cursor: followCursor } = await getFollowRecords(doc, cursor);
17
18 for (const [index, record] of follows.entries()) {
19 const doc = await resolveIdentity(record?.value?.subject);
20 const post = await getRecentPost(doc);
21
22 // it's possible that someone has never made a post i guess, we should add them to the list
23 if (!post?.records) {
24 // neg 1 can represent never made post
25 unfollows.push({ did: record?.value?.subject, lastPost: -1, uri: "" });
26 continue;
27 }
28 if (post?.records?.[0]?.value) {
29 const recentPostCreationDate = post?.records?.[0].value?.createdAt;
30 const daysSinceLastPost = getDateDifferenceInDays(
31 new Date(recentPostCreationDate),
32 new Date(),
33 );
34 if (daysSinceLastPost >= MONTHS_IN_DAYS) {
35 unfollows.push({
36 did: record?.value?.subject,
37 lastPost: daysSinceLastPost,
38 uri: record?.uri,
39 });
40 }
41 }
42
43 console.clear();
44 console.info(`Auditing user [${index + 1} / ${follows.length}]`);
45 }
46
47 cursor = followCursor;
48} while (cursor);
49
50await Bun.write("follows.json", JSON.stringify(unfollows));
51console.info(`wrote ${unfollows.length} accounts to follows.json`);