import { ActivityType, Client, Events, GatewayIntentBits, OverwriteType, PermissionFlagsBits } from 'discord.js'; import { readFileSync } from "fs"; const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildPresences, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildModeration, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages ], }); const config = JSON.parse(readFileSync("config.json", "utf-8")); const banConfig = JSON.parse(readFileSync("ban_config.json", "utf-8")); await client.login(readFileSync("token.txt", "utf-8").split("\n")[0]); const tracker = {}; for (let guild in config) { tracker[guild] = {}; for (let channel in config[guild]) { tracker[guild][channel] = new Set(); } } async function resyncChannel(channelObj) { if (tracker[channelObj.guild.id] && tracker[channelObj.guild.id][channelObj.id]) { tracker[channelObj.guild.id][channelObj.id] = new Set(channelObj.members.map((v, k) => k)); } } async function fullSync() { for (let guild in config) { const guildObj = await client.guilds.fetch(guild); for (let channel in config[guild]) { const channelObj = await guildObj.channels.fetch(channel); await resyncChannel(channelObj); await updateChannel(channelObj.id, await guildObj.channels.fetch(config[guild][channel])); } } } async function updateChannel(vcId, channelObj) { if (!tracker[channelObj.guild.id] || !tracker[channelObj.guild.id][vcId]) return; let t = tracker[channelObj.guild.id][vcId]; const permissions = channelObj.permissionOverwrites.cache.filter((v) => v.type === OverwriteType.Member); let extraneous = permissions.filter((v) => !t.has(v.id)); let missing = Array.from(t).filter(id => !permissions.has(id)); extraneous.each(v => { channelObj.permissionOverwrites.delete(v.id, "Not in VC"); }); for (let a of missing) { channelObj.permissionOverwrites.create( a, { ViewChannel: true, SendMessages: true, AddReactions: true }, { type: OverwriteType.Member, reason: "User in VC" } ); } } client.on(Events.GuildAvailable, async g => { console.log(g.name,"available"); await fullSync(); }); client.on(Events.GuildCreate, async g => { console.log(g.name,"create"); await fullSync(); }); client.on(Events.ClientReady, async () => { client.user.setActivity({ type: ActivityType.Competing, name: "best bot competition 2025" }) }) client.on(Events.MessageCreate, async m => { if (!m.guildId) { console.log("Got non-guild message"); return; } if (!banConfig[m.guildId]) { console.log("Got message in", m.guildId, "/", m.channelId, "without ban config setup."); return; } let channels = banConfig[m.guildId]; if (channels.includes(m.channelId)) { try { const dm = await m.author.createDM(); await dm.send("You have been banned for sending a message in the bot trap. Mistake? Appeal here: https://forms.gle/r41Qd12A3Df6kbm56"); } catch(e) { console.log("Failed to send message", e); } try { await m.guild.bans.create(m.author, { deleteMessageSeconds: 600, reason: "Caught in a bot trap like a stupid fly in a glue trap." }) } catch(e) { console.log("Failed to issue ban", e); } return; } }); client.on(Events.VoiceStateUpdate, async (oldState, newState) => { if (oldState.channelId === newState.channelId) return; let affectedChannels = new Set(); if (oldState.channelId && tracker[oldState.guild.id] && tracker[oldState.guild.id][oldState.channelId]) { tracker[oldState.guild.id][oldState.channelId].delete(oldState.id); affectedChannels.add(oldState.channelId); } if (newState.channelId && tracker[newState.guild.id] && tracker[newState.guild.id][newState.channelId]) { tracker[newState.guild.id][newState.channelId].add(newState.id); affectedChannels.add(newState.channelId); } for (let ch of Array.from(affectedChannels)) { if ( config[oldState.guild.id] && config[oldState.guild.id][ch]) { await updateChannel(ch, await oldState.guild.channels.fetch(config[oldState.guild.id][ch])); } } });