146 lines
3.6 KiB
JavaScript
146 lines
3.6 KiB
JavaScript
const discord = require("discord.js");
|
|
const Client = discord.Client;
|
|
const GatewayIntentBits = discord.GatewayIntentBits;
|
|
const IntentsBitField = discord.IntentsBitField;
|
|
const Intents = discord.Intents;
|
|
const Partials = discord.Partials;
|
|
const { getSetting, setSetting } = require("./settings");
|
|
const { incrementMessages } = require("./stats");
|
|
const { ensureUserForIdentity } = require("./users");
|
|
|
|
let client = null;
|
|
|
|
async function startBot({ commandRouter } = {}) {
|
|
const token = getSetting("discord_bot_token");
|
|
if (!token) {
|
|
return null;
|
|
}
|
|
|
|
const intents = [
|
|
resolveIntent("Guilds", "GUILDS"),
|
|
resolveIntent("GuildMessages", "GUILD_MESSAGES"),
|
|
resolveIntent("GuildMembers", "GUILD_MEMBERS"),
|
|
resolveIntent("MessageContent", "MESSAGE_CONTENT"),
|
|
resolveIntent("GuildVoiceStates", "GUILD_VOICE_STATES"),
|
|
resolveIntent("GuildPresences", "GUILD_PRESENCES")
|
|
].filter(Boolean);
|
|
|
|
const options = {};
|
|
if (intents.length) {
|
|
options.intents = intents;
|
|
}
|
|
console.log("Discord bot starting with intents", {
|
|
intents,
|
|
guildMembers: Boolean(resolveIntent("GuildMembers", "GUILD_MEMBERS"))
|
|
});
|
|
if (Partials?.Channel) {
|
|
options.partials = [Partials.Channel];
|
|
}
|
|
|
|
client = new Client(options);
|
|
|
|
client.on("ready", () => {
|
|
console.log(`Discord bot ready: ${client.user?.tag}`);
|
|
const avatarUrl = getBotAvatarUrl(client.user);
|
|
if (avatarUrl) {
|
|
setSetting("bot_avatar_url", avatarUrl);
|
|
}
|
|
});
|
|
|
|
client.on("messageCreate", async (message) => {
|
|
if (!message.guild || message.author.bot) {
|
|
return;
|
|
}
|
|
const displayName =
|
|
message.author.globalName || message.author.username || message.author.tag;
|
|
let avatarUrl = null;
|
|
if (typeof message.author.displayAvatarURL === "function") {
|
|
try {
|
|
avatarUrl = message.author.displayAvatarURL({ format: "png", size: 128 });
|
|
} catch {
|
|
avatarUrl = message.author.displayAvatarURL();
|
|
}
|
|
}
|
|
const profile = ensureUserForIdentity({
|
|
provider: "discord",
|
|
providerUserId: message.author.id,
|
|
displayName,
|
|
avatar: avatarUrl
|
|
});
|
|
incrementMessages(profile.id);
|
|
|
|
if (commandRouter) {
|
|
await commandRouter.handleMessage({
|
|
platform: "discord",
|
|
raw: message.content,
|
|
user: profile,
|
|
platformUser: {
|
|
id: message.author.id,
|
|
displayName,
|
|
username: message.author.username,
|
|
tag: message.author.tag,
|
|
avatar: avatarUrl
|
|
},
|
|
meta: { message, client },
|
|
reply: async (content) => {
|
|
try {
|
|
await message.reply(content);
|
|
} catch (error) {
|
|
console.error("Discord command reply failed", error);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
await client.login(token);
|
|
return client;
|
|
}
|
|
|
|
function getBotAvatarUrl(user) {
|
|
if (!user) {
|
|
return null;
|
|
}
|
|
if (typeof user.displayAvatarURL === "function") {
|
|
try {
|
|
return user.displayAvatarURL({ format: "png", size: 128 });
|
|
} catch {
|
|
return user.displayAvatarURL();
|
|
}
|
|
}
|
|
if (user.avatar) {
|
|
return `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png?size=128`;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function resolveIntent(key, legacyKey) {
|
|
if (GatewayIntentBits?.[key]) {
|
|
return GatewayIntentBits[key];
|
|
}
|
|
if (IntentsBitField?.Flags?.[key]) {
|
|
return IntentsBitField.Flags[key];
|
|
}
|
|
if (Intents?.FLAGS?.[legacyKey]) {
|
|
return Intents.FLAGS[legacyKey];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async function stopBot() {
|
|
if (client) {
|
|
await client.destroy();
|
|
client = null;
|
|
}
|
|
}
|
|
|
|
function getClient() {
|
|
return client;
|
|
}
|
|
|
|
module.exports = {
|
|
startBot,
|
|
stopBot,
|
|
getClient
|
|
};
|