bluesky-groupchat-bot/index.mjs
2024-11-04 13:41:26 -08:00

109 lines
3.1 KiB
JavaScript

import 'dotenv/config';
import {Bot, IncomingChatPreference, RichText} from "@skyware/bot";
import fetchRetry from "fetch-retry";
import { appendFileSync } from "fs";
global.fetch = fetchRetry(global.fetch);
var bot = new Bot({
emitEvents: false,
emitChatEvents: true
});
bot.on("error", error => {
console.error("bot error", error);
});
await bot.login({
identifier: process.env.IDENTIFIER,
password: process.env.PASSWORD
});
await bot.setChatPreference(IncomingChatPreference.All);
bot.on("message", async message => {
try {
var sender = await message.getSender();
var conversation = await message.getConversation();
if (!conversation) { console.error("missing conversation"); }
if (message.text.startsWith('/')) {
let respond = text => conversation.sendMessage({text});
let cmd = message.text.split(' ')[0].slice(1).toLowerCase();
let commandList = `/list, /leave, /join, /ping`;
switch(cmd) {
case "ping":
await respond("pong");
return;
case "list":
let {conversations} = await bot.listConversations();
await respond(`${conversations.length} members in group chat: ${conversations.map(c => '@' + c.members.find(m => m.did != bot.profile.did).handle).join(', ')}`);
return;
case "leave":
await respond(`You left the group chat and will no longer receive messages! Send any message to join again, or send /join to re-join silently.`);
await conversation.leave();
return;
case "join":
await respond(`You joined the group chat`);
return;
case "help":
await respond(`Commands: ${commandList}`);
return;
default:
await respond(`Only these commands are accepted: ${commandList}`);
return;
}
}
var logline = `${message.sentAt.toISOString()},${message.senderDid},${sender.displayName},${sender.handle},${message.text}`;
console.log(logline);
appendFileSync(`chatlog.csv`, logline + '\n');
var text = message.text;
var facets = message.facets || [];
var linkedName = sender.displayName || sender.handle;
var prefix = `${linkedName}: `;
var prefixByteLength = new Blob([prefix]).size;
facets = facets.map(f => {
var facet = f.toRecord();
facet.index.byteStart += prefixByteLength;
facet.index.byteEnd += prefixByteLength;
return facet;
});
text = prefix + text;
facets.unshift({
index: {
byteStart: 0,
byteEnd: new Blob([linkedName]).size
},
features: [{
did: sender.did,
"$type": "app.bsky.richtext.facet#mention"
}]
});
var {conversations} = await bot.listConversations();
var otherConservations = conversations.filter(c => c.id != conversation?.id);
//otherConservations = otherConservations.filter(c => c.members.length > 1); // doesn't work, bsky doesnt let you know when they leave?
var messages = otherConservations.map(c => ({
conversationId: c.id,
text,
facets
}));
await bot.sendMessages(messages, {resolveFacets: false});
} catch (error) {
console.error(error);
conversation?.sendMessage({text: error.message}).catch(error => console.error(error));
}
});
global.bot = bot;