Lumi/src/services/discord.js
2026-05-30 22:07:04 +02:00

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