Pronouns labels on Bluesky
1import { AppBskyActorDefs, ComAtprotoLabelDefs } from "@atproto/api";
2import { DID, PRONOUNS, SIGNING_KEY, URIs } from "./constants.js";
3import { LabelerServer } from "@skyware/labeler";
4import Database from "better-sqlite3";
5
6const server = new LabelerServer({ did: DID, signingKey: SIGNING_KEY });
7
8const db = new Database("labels.db");
9db.pragma("journal_mode = WAL");
10
11server.start(4001, (error, address) => {
12 if (error) {
13 console.error(error);
14 } else {
15 console.log(`Labeler server listening on ${address}`);
16 }
17});
18
19export const label = async (
20 subject: string | AppBskyActorDefs.ProfileView,
21 uri: string,
22) => {
23 const did = AppBskyActorDefs.isProfileView(subject) ? subject.did : subject;
24
25 const query = db
26 .prepare<
27 unknown[],
28 ComAtprotoLabelDefs.Label
29 >(`SELECT * FROM labels WHERE uri = ?`)
30 .all(did);
31
32 const labels = query.reduce((set, label) => {
33 if (!label.neg) set.add(label.val);
34 else set.delete(label.val);
35 return set;
36 }, new Set<string>());
37
38 const post = URIs[uri];
39
40 if (post?.includes("Like this post to delete")) {
41 await server
42 .createLabels({ uri: did }, { negate: [...labels] })
43 .catch((err) => {
44 console.log(err);
45 })
46 .then(() => console.log(`Deleted labels for ${did}`));
47 } else if (labels.size < 4 && PRONOUNS[post]) {
48 await server
49 .createLabel({
50 src: server.did,
51 uri: did,
52 val: PRONOUNS[post],
53 cts: new Date().toISOString(),
54 })
55 .catch((err) => {
56 console.log(err);
57 })
58 .then(() => console.log(`Labeled ${did} with ${post}`));
59 }
60};