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};