From 99b962db2ea0d983899b8e2871f153d8c7edd3e2 Mon Sep 17 00:00:00 2001 From: AnxietyisReal <96593068+AnxietyisReal@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:49:24 +1000 Subject: [PATCH] Major bot improvements Half of them is untested on development bot so I wouldn't be surprised if I broke it in production. --- src/client.ts | 26 +++++---------------- src/commands/bonk.ts | 3 +-- src/commands/inviteinfo.ts | 3 +-- src/commands/mp.ts | 13 +++++------ src/commands/music.ts | 3 +-- src/commands/ping.ts | 3 +-- src/commands/purge.ts | 3 +-- src/commands/randomcolor.ts | 2 +- src/commands/rank.ts | 35 +++++++++-------------------- src/commands/roleinfo.ts | 7 +++--- src/commands/statistics.ts | 2 +- src/commands/suggest.ts | 8 +++---- src/commands/whois.ts | 4 ++-- src/events/guildBanAdd.ts | 3 +-- src/events/guildBanRemove.ts | 3 +-- src/events/guildMemberAdd.ts | 3 +-- src/events/inviteCreate.ts | 3 +-- src/events/messageCreate.ts | 4 ++-- src/events/messageDelete.ts | 3 +-- src/events/messageReactionRemove.ts | 3 +-- src/events/messageUpdate.ts | 3 +-- src/index.ts | 10 +++------ 22 files changed, 51 insertions(+), 96 deletions(-) diff --git a/src/client.ts b/src/client.ts index bc4ba12..70eff74 100644 --- a/src/client.ts +++ b/src/client.ts @@ -12,7 +12,7 @@ import MPServer from './models/MPServer.js'; import xjs from 'xml-js'; import axios from 'axios'; import moment from 'moment'; -import tokens from './tokens.json' assert { type: 'json'}; +import tokens from './tokens.json' assert {type: 'json'}; let importconfig:Config try{ @@ -160,14 +160,6 @@ export default class TClient extends Client { logTime = ()=>`[${this.moment().format('DD/MM/YY HH:mm:ss')}]`; - alignText(text: string, length: number, alignment: string, emptyChar = ' '){ - if (alignment == 'right') text = emptyChar.repeat(length - text.length)+text; - else if (alignment == 'middle'){ - const emptyCharsPerSide = (length - text.length)/2; - text = emptyChar.repeat(Math.floor(emptyCharsPerSide))+text+emptyChar.repeat(Math.floor(emptyCharsPerSide)); - } else text = text + emptyChar.repeat(length - text.length); - return text; - } async punish(interaction: Discord.ChatInputCommandInteraction<'cached'>, type: string){ if (!this.isStaff(interaction.member as Discord.GuildMember)) return this.youNeedRole(interaction, "dcmod"); @@ -187,21 +179,19 @@ export default class TClient extends Client { } async YTLoop(YTChannelID: string, YTChannelName: string, DCChannelID: string){ let Data:any; - let error; try { - await this.axios.get(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {timeout: 5000}).then((xml:any)=>Data = this.xjs.xml2js(xml.data, {compact: true})) + await this.axios.get(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {timeout: 5000}).then(xml=>Data = this.xjs.xml2js(xml.data, {compact: true})) } catch(err){ - error = true; console.log(this.logTime(), `${YTChannelName} YT fail`) } if (!Data) return; - if (this.YTCache[YTChannelID] == undefined){ + if (this.YTCache[YTChannelID] === undefined){ this.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text; return; } - if (Data.feed.entry[1]['yt:videoId']._text == this.YTCache[YTChannelID]){ + if (Data.feed.entry[1]['yt:videoId']._text === this.YTCache[YTChannelID]){ this.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text; (this.channels.resolve(DCChannelID) as Discord.TextChannel).send(`**${YTChannelName}** just uploaded a video!\n${Data.feed.entry[0].link._attributes.href}`) } @@ -210,19 +200,15 @@ export default class TClient extends Client { formatBytes(bytes:number, decimals:number = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; - const dm = decimals < 0 ? 0 : decimals; - const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); - return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; + return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals < 0 ? 0 : decimals)) + ' ' + ['Bytes', 'KB', 'MB', 'GB'][i]; }; } export class WClient extends WebhookClient { tokens: Tokens; constructor(){ - super({ - url: tokens.webhook_url - }) + super({url: tokens.webhook_url}) this.tokens = tokens as Tokens; } } diff --git a/src/commands/bonk.ts b/src/commands/bonk.ts index 2665e61..c420721 100644 --- a/src/commands/bonk.ts +++ b/src/commands/bonk.ts @@ -5,8 +5,7 @@ export default { //if (!client.isStaff(interaction.member) && interaction.channelId == '468835415093411863') return interaction.reply('This command is restricted to staff only in this channel due to high usage.') const member = interaction.options.getMember('member') as Discord.GuildMember; const reason = interaction.options.getString('reason'); - const adminPerm = member.permissions.has('Administrator'); - if (adminPerm) return interaction.reply('You cannot bonk an admin!'); + if (member.permissions.has('Administrator')) return interaction.reply('You cannot bonk an admin!'); await client.bonkCount._incrementUser(member.id); interaction.reply({embeds: [new client.embed().setColor(client.config.embedColor) diff --git a/src/commands/inviteinfo.ts b/src/commands/inviteinfo.ts index d2221e9..48d2aef 100644 --- a/src/commands/inviteinfo.ts +++ b/src/commands/inviteinfo.ts @@ -2,8 +2,7 @@ import Discord from 'discord.js'; import TClient from '../client.js'; export default { async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ - const inviteCode = interaction.options.getString('code',true).replace(/(https:\/\/|discord.gg\/)/g,'') - await client.axios.get(`https://discord.com/api/v${Discord.APIVersion}/invites/${inviteCode}`).then(async inviteInfo=> + await client.axios.get(`https://discord.com/api/v${Discord.APIVersion}/invites/${interaction.options.getString('code',true).replace(/(https:\/\/|discord.gg\/)/g,'')}`).then(async inviteInfo=> await interaction.reply({embeds: [ new client.embed().setColor(client.config.embedColor).setURL(`https://discord.gg/${inviteInfo.data.code}`).setTitle(inviteInfo.data.guild.name).setDescription([ `ID: \`${inviteInfo.data.guild.id}\``, diff --git a/src/commands/mp.ts b/src/commands/mp.ts index 1cb70f9..094bb60 100644 --- a/src/commands/mp.ts +++ b/src/commands/mp.ts @@ -26,7 +26,7 @@ async function MPdata(client:TClient, interaction:Discord.ChatInputCommandIntera export default { run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ if (interaction.channelId === '468835769092669461' && !client.isStaff(interaction.member) && ['status', 'players'].includes(interaction.options.getSubcommand())) { - interaction.reply(`Please use <#739084625862852715> for \`/mp status/players\` commands to prevent clutter in this channel.`).then(msg=>setTimeout(()=>interaction.deleteReply(), 6000)); + interaction.reply(`Please use <#739084625862852715> for \`/mp status/players\` commands to prevent clutter in this channel.`).then(()=>setTimeout(()=>interaction.deleteReply(), 6000)); return; } ({ @@ -93,7 +93,6 @@ export default { } }, players: async()=>{ - const embed1 = new client.embed(); const data = JSON.parse(readFileSync(path.join('src/database/MPPlayerData.json'), {encoding: 'utf8'})).slice(client.statsGraph) // handle negative days data.forEach((change: number, i: number) => { @@ -235,15 +234,15 @@ export default { const ty = graphOrigin[1] + graphSize[1] + (textSize); ctx.fillText('time ->', tx, ty); - const Image = new client.attachmentBuilder(img.toBuffer(),{name: 'FSStats.png'}) - embed1.setImage('attachment://FSStats.png') + const embed1 = new client.embed(); const FSserver1 = await MPdata(client, interaction, embed1) if (!FSserver1?.data) return console.log('FSserver1 failed - players') - embed1.setTitle(FSserver1?.data.server.name.length == 0 ? 'Offline' : FSserver1?.data.server.name) + embed1.setTitle(FSserver1?.data.server.name.length === 0 ? 'Offline' : FSserver1?.data.server.name) .setDescription(`${FSserver1?.data.slots.used}/${FSserver1?.data.slots.capacity}`) - .setColor(FSserver1?.data.server.name.length == 0 ? client.config.embedColorRed : client.config.embedColor); + .setColor(FSserver1?.data.server.name.length === 0 ? client.config.embedColorRed : client.config.embedColor) + .setImage('attachment://FSStats.png'); FSserver1?.data.slots.players.filter(x=>x.isUsed).forEach(player=>embed1.addFields({name: `${player.name} ${player.isAdmin ? '| admin' : ''}`, value: `Farming for ${client.formatPlayerUptime(player.uptime)}`})) - interaction.reply({embeds: [embed1], files: [Image]}) + interaction.reply({embeds: [embed1], files: [new client.attachmentBuilder(img.toBuffer(),{name:'FSStats.png'})]}) }, maintenance: ()=>{ if (client.config.mainServer.id == interaction.guildId) { diff --git a/src/commands/music.ts b/src/commands/music.ts index 78f8f98..f12c88d 100644 --- a/src/commands/music.ts +++ b/src/commands/music.ts @@ -11,8 +11,7 @@ export default { clientId: client.tokens.dontlookatme.client, clientSecret: client.tokens.dontlookatme.secret }); - const voiceCh = interaction.member.voice.channel; - if (!voiceCh) return interaction.reply('Please join a voice channel first to use the command.'); + if (!interaction.member.voice.channel) return interaction.reply('Please join a voice channel first to use the command.'); player.nodes.create(interaction.guildId, { metadata: { channel: interaction.channel, diff --git a/src/commands/ping.ts b/src/commands/ping.ts index dd1082d..a123ac9 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -3,8 +3,7 @@ import TClient from '../client.js'; export default { async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ const msg = await interaction.reply({content: 'Pinging...', fetchReply: true}) - const time = msg.createdTimestamp - interaction.createdTimestamp; - msg.edit(`Websocket: \`${client.formatTime(client.ws.ping, 3, {longNames: false, commas: true})}\`\nBot: \`${client.formatTime(time, 3, {longNames: false, commas: true})}\``) + msg.edit(`Websocket: \`${client.formatTime(client.ws.ping, 3, {longNames: false, commas: true})}\`\nBot: \`${client.formatTime(msg.createdTimestamp - interaction.createdTimestamp, 3, {longNames: false, commas: true})}\``) }, data: new Discord.SlashCommandBuilder() .setName('ping') diff --git a/src/commands/purge.ts b/src/commands/purge.ts index defc0f9..3a25c7d 100644 --- a/src/commands/purge.ts +++ b/src/commands/purge.ts @@ -8,12 +8,11 @@ export default { const amount = interaction.options.getInteger('amount') as number; if (amount > 100) return interaction.reply({content: 'Discord API limits purging up to 100 messages.', ephemeral: true}) const user = interaction.options.getUser('user'); - let messagesArray: Array = []; if (user){ (interaction.channel as Discord.TextChannel).messages.fetch({limit: amount}).then(msgs=>{ - const msgList = msgs.filter(x=>x.author.id == user.id); + const msgList = msgs.filter(x=>x.author.id === user.id); (interaction.channel as Discord.TextChannel).bulkDelete(msgList); }) } else { diff --git a/src/commands/randomcolor.ts b/src/commands/randomcolor.ts index 15f08e3..d856cb4 100644 --- a/src/commands/randomcolor.ts +++ b/src/commands/randomcolor.ts @@ -3,7 +3,7 @@ import TClient from '../client.js'; export default { run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ const embed = new client.embed().setColor(Math.floor(Math.random()*16777215)); - embed.addFields({name: 'Hex code', value: `#${embed.data.color.toString(16).toUpperCase()}`}); + embed.addFields({name: 'Hex code', value: '#'+embed.data.color.toString(16).toUpperCase()}); interaction.reply({embeds: [embed]}); }, data: new Discord.SlashCommandBuilder() diff --git a/src/commands/rank.ts b/src/commands/rank.ts index 2ac230e..1aa538c 100644 --- a/src/commands/rank.ts +++ b/src/commands/rank.ts @@ -10,7 +10,7 @@ export default { ({ view: async()=>{ // fetch user or user interaction sender - const member = interaction.options.getMember("member") ?? interaction.member as Discord.GuildMember; + const member = interaction.options.getMember('member') ?? interaction.member as Discord.GuildMember; if (member.user.bot) return interaction.reply('Bots don\'t level up, try viewing the rank data from the users instead.'); // information about users progress on level roles const userData = await client.userLevels._content.findById(member.user.id); @@ -27,13 +27,8 @@ export default { interaction.reply({embeds: [new client.embed().setColor(member.displayColor).setTitle(`Level: **${userData.level}**\nRank: **${index ? '#' + index : 'last'}**\nProgress: **${memberDifference}/${levelDifference} (${(memberDifference/levelDifference*100).toFixed(2)}%)**\nTotal: **${userData.messages.toLocaleString('en-US')}**`).setThumbnail(member.avatarURL({extension:'png',size:1024}) || member.user.avatarURL({extension:'png',size:1024}) || member.user.defaultAvatarURL).setFooter({text: userData.notificationPing === true ? 'Ping notification enabled' : 'Ping notification disabled'})]}) }, leaderboard: ()=>{ - const messageCountsTotal = allData.reduce((a, b) => a + b.messages, 0); - const timeActive = Math.floor((Date.now() - client.config.LRSstart)/1000/60/60/24); - - const dailyMsgsPath = path.join('./src/database/dailyMsgs.json'); - const data = JSON.parse(readFileSync(dailyMsgsPath, 'utf8')).map((x: Array, i: number, a: any) => { - const yesterday = a[i - 1] || []; - return x[1] - (yesterday[1] || x[1]); + const data = JSON.parse(readFileSync(path.join('./src/database/dailyMsgs.json'), 'utf8')).map((x: Array, i: number, a: any) => { + return x[1] - (a[i - 1] || [][1] || x[1]) }).slice(1).slice(-60); // handle negative days @@ -130,32 +125,24 @@ export default { ctx.fillStyle = 'white'; // highest value - const maxx = graphOrigin[0] + graphSize[0] + textSize; - const maxy = previousY[0] + (textSize / 3); - ctx.fillText(previousY[1].toLocaleString('en-US'), maxx, maxy); + ctx.fillText(previousY[1].toLocaleString('en-US'), graphOrigin[0] + graphSize[0] + textSize, previousY[0] + (textSize / 3)); // lowest value - const lowx = graphOrigin[0] + graphSize[0] + textSize; - const lowy = graphOrigin[1] + graphSize[1] + (textSize / 3); - ctx.fillText('0 msgs', lowx, lowy); + ctx.fillText('0 msgs', graphOrigin[0] + graphSize[0] + textSize, graphOrigin[1] + graphSize[1] + (textSize / 3)); // 30d ctx.fillText('30d ago', lastMonthStart, graphOrigin[1] - (textSize / 3)); // time -> - const tx = graphOrigin[0] + (textSize / 2); - const ty = graphOrigin[1] + graphSize[1] + (textSize); - ctx.fillText('time ->', tx, ty); + ctx.fillText('time ->', graphOrigin[0] + (textSize / 2), graphOrigin[1] + graphSize[1] + (textSize)); - const topUsers = allData.sort((a,b)=>b.messages - a.messages).slice(0,10).map((x,i)=>`\`${i+1}.\` <@${x._id}>: ${x.messages.toLocaleString('en-US')}`).join('\n'); - - const graphImage = new client.attachmentBuilder(img.toBuffer(), {name: 'dailymsgs.png'}) - const embed = new client.embed().setTitle('Ranking leaderboard') - .setDescription(`Level System was created **${timeActive}** days ago. Since then, a total of **${messageCountsTotal.toLocaleString('en-US')}** messages have been sent in this server.`) - .addFields({name: 'Top users by messages sent:', value: topUsers}) + interaction.reply({embeds: [ + new client.embed().setTitle('Ranking leaderboard') + .setDescription(`Level System was created **${Math.floor((Date.now()-client.config.LRSstart)/1000/60/60/24)}** days ago. Since then, a total of **${allData.reduce((a, b)=>a+b.messages, 0).toLocaleString('en-US')}** messages have been sent in this server.`) + .addFields({name: 'Top users by messages sent:', value: allData.sort((a,b)=>b.messages - a.messages).slice(0,10).map((x,i)=>`\`${i+1}.\` <@${x._id}>: ${x.messages.toLocaleString('en-US')}`).join('\n')}) .setImage('attachment://dailymsgs.png').setColor(client.config.embedColor) .setFooter({text: 'Graph updates daily.'}) - interaction.reply({embeds: [embed], files: [graphImage]}) + ], files: [new client.attachmentBuilder(img.toBuffer(),{name: 'dailymsgs.png'})]}) }, notification: async()=>{ const findUserInMongo = await client.userLevels._content.findById(interaction.user.id); diff --git a/src/commands/roleinfo.ts b/src/commands/roleinfo.ts index 01cc259..e3ca7f3 100644 --- a/src/commands/roleinfo.ts +++ b/src/commands/roleinfo.ts @@ -4,14 +4,13 @@ export default { run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ const role = interaction.options.getRole('role') as Discord.Role; const permissions = role.permissions.toArray(); - const Role = role.members.map((e:Discord.GuildMember)=>`**${e.user.username}**`).join('\n') || ''; interaction.reply({embeds: [new client.embed().setColor(role.color || '#fefefe').setThumbnail(role?.iconURL()).setTitle(`Role Info: ${role.name}`).addFields( {name: '🔹 ID', value: `\`${role.id}\``, inline: true}, {name: '🔹 Color', value: `\`${role.hexColor}\``, inline: true}, {name: '🔹 Creation Date', value: `\n`, inline: true}, - {name: '🔹 Misc', value: `Hoist: \`${role.hoist}\`\nMentionable: \`${role.mentionable}\`\nPosition: \`${role.position}\` from bottom\nMembers: \`${role.members.size}\`\n${role.members.size < 21 ? Role : ''}`, inline: true}, - {name: '🔹 Permissions', value: `${permissions.includes('Administrator') ? ['Administrator'] : permissions.join(', ') || 'None'}`, inline: true} - )]}) + {name: '🔹 Misc', value: `Hoist: \`${role.hoist}\`\nMentionable: \`${role.mentionable}\`\nPosition: \`${role.position}\` from bottom\nMembers: \`${role.members.size}\`\n${role.members.size < 21 ? role.members.map((e:Discord.GuildMember)=>`**${e.user.username}**`).join('\n') || '' : ''}`, inline: true}, + {name: '🔹 Permissions', value: `${permissions.includes('Administrator') ? ['Administrator'] : permissions.join(', ').replace(/([a-z])([A-Z])/g, '$1 $2') || 'No permissions'}`, inline: true} + )]})// https://stackoverflow.com/questions/15343163/add-a-space-between-two-words - For anonymous programmer, you know who I am talking to. You're welcome... }, data: new Discord.SlashCommandBuilder() .setName('roleinfo') diff --git a/src/commands/statistics.ts b/src/commands/statistics.ts index 1af3745..5d149f7 100644 --- a/src/commands/statistics.ts +++ b/src/commands/statistics.ts @@ -13,7 +13,7 @@ export default { const columns = ['Command name', 'Count']; const includedCommands = client.commands.filter(x=>x.uses).sort((a,b)=>b.uses - a.uses); - if (includedCommands.size == 0) return interaction.reply(`No commands have been used yet.\nUptime: **${client.formatTime(client.uptime as number, 3, {longNames: true, commas: true})}**`); + if (includedCommands.size === 0) return interaction.reply(`No commands have been used yet.\nUptime: **${client.formatTime(client.uptime as number, 3, {longNames: true, commas: true})}**`); const nameLength = Math.max(...includedCommands.map(x=>x.command.default.data.name.length), columns[0].length) + 2; const amountLength = Math.max(...includedCommands.map(x=>x.uses.toString().length), columns[1].length) + 1; const rows = [`${columns[0] + ' '.repeat(nameLength - columns[0].length)}|${' '.repeat(amountLength - columns[1].length) + columns[1]}\n`, '-'.repeat(nameLength) + '-'.repeat(amountLength) + '\n']; diff --git a/src/commands/suggest.ts b/src/commands/suggest.ts index a96bdd4..47c1747 100644 --- a/src/commands/suggest.ts +++ b/src/commands/suggest.ts @@ -36,12 +36,12 @@ export default { if (client.config.mainServer.id === interaction.guildId) { if (!interaction.member.roles.cache.has(client.config.mainServer.roles.bottech)) return client.youNeedRole(interaction, 'bottech'); } - if ((await client.suggestion._content.findById(suggestionIDReply)).state == 'Rejected') return interaction.reply({content: 'This suggestion\'s state is locked and cannot be modified.', ephemeral: true}); + if ((await client.suggestion._content.findById(suggestionIDReply)).state === 'Rejected') return interaction.reply({content: 'This suggestion\'s state is locked and cannot be modified.', ephemeral: true}); (await client.users.fetch(userid)).send({embeds: [new client.embed() .setColor(client.config.embedColorGreen) .setAuthor({name: interaction.user.username, iconURL: interaction.user.avatarURL({size: 256})}) .setTitle('Your suggestion has been approved.') - .setDescription(`> **Your suggestion:**\n${theirIdea}\n> **Their message:**\n${replyInDM.length == null ? '*No message from them.*' : replyInDM}`) + .setDescription(`> **Your suggestion:**\n${theirIdea}\n> **Their message:**\n${replyInDM.length === null ? '*No message from them.*' : replyInDM}`) .setFooter({text: `Timestamp: ${timeFormatting} | Suggestion ID: ${suggestionIDReply}`}) ]}); await client.suggestion._content.findByIdAndUpdate(suggestionIDReply, {state: 'Approved'}); @@ -51,12 +51,12 @@ export default { if (client.config.mainServer.id === interaction.guildId) { if (!interaction.member.roles.cache.has(client.config.mainServer.roles.bottech)) return client.youNeedRole(interaction, 'bottech'); } - if ((await client.suggestion._content.findById(suggestionIDReply)).state == 'Approved') return interaction.reply({content: 'This suggestion\'s state is locked and cannot be modified.', ephemeral: true}); + if ((await client.suggestion._content.findById(suggestionIDReply)).state === 'Approved') return interaction.reply({content: 'This suggestion\'s state is locked and cannot be modified.', ephemeral: true}); (await client.users.fetch(userid)).send({embeds: [new client.embed() .setColor(client.config.embedColorRed) .setAuthor({name: interaction.user.username, iconURL: interaction.user.avatarURL({size: 256})}) .setTitle('Your suggestion has been rejected.') - .setDescription(`> **Your suggestion:**\n${theirIdea}\n> **Their message:**\n${replyInDM.length == null ? '*No message from them.*' : replyInDM}`) + .setDescription(`> **Your suggestion:**\n${theirIdea}\n> **Their message:**\n${replyInDM.length === null ? '*No message from them.*' : replyInDM}`) .setFooter({text: `Timestamp: ${timeFormatting} | Suggestion ID: ${suggestionIDReply}`}) ]}); await client.suggestion._content.findByIdAndUpdate(suggestionIDReply, {state: 'Rejected'}); diff --git a/src/commands/whois.ts b/src/commands/whois.ts index 7007ecd..4adfc65 100644 --- a/src/commands/whois.ts +++ b/src/commands/whois.ts @@ -15,14 +15,14 @@ export default { const member = interaction.options.getMember('member') as Discord.GuildMember; if (member === null){ const user = interaction.options.getUser('member') as Discord.User; - const embed = new client.embed() + interaction.reply({embeds: [new client.embed() .setColor(client.config.embedColor) .setURL(`https://discord.com/users/${user.id}`) .setThumbnail(user.avatarURL({size:2048}) || user.defaultAvatarURL) .setTitle(`${user.bot ? 'Bot' : 'User'} Info: ${user.username}`) .setDescription(`<@${user.id}>\n\`${user.id}\``) .addFields({name: '🔹 Account Creation Date', value: `\n`}) - interaction.reply({embeds: [embed]}) + ]}) } else { await member.user.fetch(); const presence = member.presence?.clientStatus as Discord.ClientPresenceStatusData; diff --git a/src/events/guildBanAdd.ts b/src/events/guildBanAdd.ts index 2446d25..64b43c6 100644 --- a/src/events/guildBanAdd.ts +++ b/src/events/guildBanAdd.ts @@ -3,8 +3,7 @@ import TClient from '../client.js'; export default { async run(client:TClient, member:Discord.GuildMember){ if (member.guild?.id != client.config.mainServer.id) return; - const fetchBanlog = await member.guild.fetchAuditLogs({limit: 1, type: AuditLogEvent.MemberBanAdd}) - const banLog = fetchBanlog.entries.first(); + const banLog = (await member.guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberBanAdd })).entries.first(); if (!banLog) return console.log(`Member was banned from ${member.guild.name} but no audit log for this member.`) const {executor, target, reason } = banLog; if (target.id === member.user.id) { diff --git a/src/events/guildBanRemove.ts b/src/events/guildBanRemove.ts index 7c7aced..60122a8 100644 --- a/src/events/guildBanRemove.ts +++ b/src/events/guildBanRemove.ts @@ -3,8 +3,7 @@ import TClient from '../client.js'; export default { async run(client:TClient, member:Discord.GuildMember){ if (member.guild?.id != client.config.mainServer.id) return; - const fetchUnbanlog = await member.guild.fetchAuditLogs({limit: 1, type: AuditLogEvent.MemberBanRemove}) - const unbanLog = fetchUnbanlog.entries.first(); + const unbanLog = (await member.guild.fetchAuditLogs({limit: 1, type: AuditLogEvent.MemberBanRemove})).entries.first(); if (!unbanLog) return console.log(`User was unbanned from ${member.guild.name} but no audit log for this user.`) const { executor, target, reason } = unbanLog; if (target.id === member.user.id) (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [ diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts index 5e2fc9f..c643738 100644 --- a/src/events/guildMemberAdd.ts +++ b/src/events/guildMemberAdd.ts @@ -21,13 +21,12 @@ export default { const newInvites = await member.guild.invites.fetch(); const usedInvite = newInvites.find((inv:Discord.Invite)=>client.invites.get(inv.code)?.uses < inv.uses); newInvites.forEach((inv:Discord.Invite)=>client.invites.set(inv.code,{uses: inv.uses, creator: inv.inviterId, channel: inv.channel.name})); - const evadedCase = await client.punishments._content.findOne({'member': member.user.id, type: 'mute', expired: undefined}); (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [ new client.embed().setColor(client.config.embedColorGreen).setTimestamp().setThumbnail(member.user.displayAvatarURL({size: 2048})).setTitle(`${isBot} Joined: ${member.user.username}`).setDescription(`<@${member.user.id}>\n\`${member.user.id}\``).setFooter({text: `Total members: ${index}${suffix}`}).addFields( {name: '🔹 Account Creation Date', value: `\n`}, {name: '🔹 Invite Data:', value: usedInvite ? `Invite: \`${usedInvite.code}\`\nCreated by: **${usedInvite.inviter?.username}**\nChannel: **#${usedInvite.channel.name}**` : 'No invite data could be fetched.'} )]}); - if (evadedCase){ + if (await client.punishments._content.findOne({'member': member.user.id, type: 'mute', expired: undefined})){ (client.channels.resolve(client.config.mainServer.channels.dcmod_chat) as Discord.TextChannel).send({embeds: [new client.embed().setColor(client.config.embedColorYellow).setTitle('Case evasion detected').setDescription([ `**${member.user.username}** (\`${member.user.id}\`) has been detected for case evasion.`, 'Timeout has been automatically added. (25 days)' diff --git a/src/events/inviteCreate.ts b/src/events/inviteCreate.ts index aff3e8f..339db1a 100644 --- a/src/events/inviteCreate.ts +++ b/src/events/inviteCreate.ts @@ -3,7 +3,6 @@ import TClient from '../client.js'; export default { async run(client:TClient, invite: Discord.Invite){ if (!invite.guild) return; - const newInvites = await (invite.guild as Discord.Guild).invites.fetch(); - newInvites.forEach(inv=>client.invites.set(inv.code,{uses: inv.code, creator: inv.inviterId, channel: inv.channel.name})) + (await (invite.guild as Discord.Guild).invites.fetch()).forEach(inv=>client.invites.set(inv.code,{uses: inv.code, creator: inv.inviterId, channel: inv.channel.name})) } } diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index a40b799..df9cd27 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -6,7 +6,7 @@ export default { const msgarr = message.content.toLowerCase().replaceAll(/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\n?1234567890]/g, '').split(' '); let automodded: boolean; - const Whitelist = [] // Array of channel ids for automod to be disabled in (Disables bannedWords and advertisement, mind you.) + //const Whitelist = [] // Array of channel ids for automod to be disabled in (Disables bannedWords and advertisement, mind you.) async function repeatedMessages(thresholdTime:number, thresholdAmount:number, type:string, muteTime:string, muteReason:string){ if (client.repeatedMessages[message.author.id]){ @@ -35,7 +35,7 @@ export default { } if (client.config.botSwitches.automod && !message.member.roles.cache.has(client.config.mainServer.roles.admin) && message.guildId == client.config.mainServer.id){ - if (await client.bannedWords._content.findById(msgarr) && !Whitelist.includes(message.channelId)){ + if (await client.bannedWords._content.findById(msgarr)/* && !Whitelist.includes(message.channelId) */){ automodded = true; message.delete().catch(()=>console.log('bannedWords automod; msg got possibly deleted by another bot.')); message.channel.send('That word isn\'t allowed here.').then(x=>setTimeout(()=>x.delete(), 10000)); diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts index 92a5a15..817d765 100644 --- a/src/events/messageDelete.ts +++ b/src/events/messageDelete.ts @@ -3,7 +3,6 @@ import TClient from '../client.js'; export default { run(client:TClient, msg:Discord.Message){ if (!client.config.botSwitches.logs) return; - const channel = client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel; const disabledChannels = ['548032776830582794', '541677709487505408', '949380187668242483'] if (msg.guild?.id != client.config.mainServer.id || msg.partial || msg.author.bot || disabledChannels.includes(msg.channelId)) return; if (Discord.DiscordAPIError.name === '10008') return console.log(client.logTime(), 'Caught an unexpected error returned by Discord API. (Unknown Message)'); @@ -15,6 +14,6 @@ export default { ) const attachments: Array = []; msg.attachments.forEach(x=>attachments.push(x.url)); - channel.send({embeds: [embed], files: attachments}) + (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [embed], files: attachments}) } } diff --git a/src/events/messageReactionRemove.ts b/src/events/messageReactionRemove.ts index c21ade4..36cee0e 100644 --- a/src/events/messageReactionRemove.ts +++ b/src/events/messageReactionRemove.ts @@ -2,8 +2,7 @@ import Discord from 'discord.js'; import TClient from '../client.js'; export default { run(client:TClient, reaction:Discord.MessageReaction, user:Discord.User){ - if (!client.config.botSwitches.logs) return; - if (reaction.message.guildId != client.config.mainServer.id || reaction.message.partial) return; + if (!client.config.botSwitches.logs || reaction.message.guildId != client.config.mainServer.id || reaction.message.partial) return; if (reaction.emoji.name === '🖕') return (client.channels.cache.get(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds:[new client.embed().setColor(client.config.embedColorRed).setTimestamp().setAuthor({name: `Author: ${user.username} (${user.id})`, iconURL: `${user.displayAvatarURL()}`}).setTitle('Message reaction').setDescription(`<@${user.id}>\nRemoved a reaction from the message.\n**Emoji**\n${reaction.emoji.name}\n**Channel**\n<#${reaction.message.channelId}>`)]}) } } diff --git a/src/events/messageUpdate.ts b/src/events/messageUpdate.ts index 8565079..97ef122 100644 --- a/src/events/messageUpdate.ts +++ b/src/events/messageUpdate.ts @@ -3,8 +3,7 @@ import TClient from '../client.js'; export default { async run(client:TClient, oldMsg:Discord.Message, newMsg:Discord.Message){ if (!client.config.botSwitches.logs) return; - const disabledChannels = ['548032776830582794', '541677709487505408', '949380187668242483'] - if (oldMsg.guild?.id != client.config.mainServer.id || oldMsg.author === null || oldMsg?.author.bot || oldMsg.partial || newMsg.partial || !newMsg.member || disabledChannels.includes(newMsg.channelId)) return; + if (oldMsg.guild?.id != client.config.mainServer.id || oldMsg.author === null || oldMsg?.author.bot || oldMsg.partial || newMsg.partial || !newMsg.member || ['548032776830582794', '541677709487505408', '949380187668242483'].includes(newMsg.channelId)) return; if (await client.bannedWords._content.findOne({_id:newMsg.content.toLowerCase().replaceAll(/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\n]/g, ' ').split(' ')}) && (!client.isStaff(newMsg.member))) newMsg.delete(); if (newMsg.content === oldMsg.content) return; (client.channels.resolve(client.config.mainServer.channels.logs) as Discord.TextChannel).send({embeds: [new client.embed().setColor(client.config.embedColor).setTimestamp().setAuthor({name: `Author: ${oldMsg.author.username} (${oldMsg.author.id})`, iconURL: `${oldMsg.author.displayAvatarURL()}`}).setTitle('Message edited').setDescription(`<@${oldMsg.author.id}>\nOld content:\n\`\`\`\n${oldMsg.content.length < 1 ? '(Attachment)' : oldMsg.content}\n\`\`\`\nNew content:\n\`\`\`\n${newMsg.content}\`\`\`\nChannel: <#${oldMsg.channelId}>`)], components: [new Discord.ActionRowBuilder().addComponents(new Discord.ButtonBuilder().setStyle(5).setURL(`${oldMsg.url}`).setLabel('Jump to message'))]}); diff --git a/src/index.ts b/src/index.ts index ebb6dec..2618163 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,9 +31,7 @@ client.on('ready', async()=>{ function DZ(error:Error, type:string){// Yes, I may have shiternet but I don't need to wake up to like a hundred messages or so. if (['getaddrinfo ENOTFOUND discord.com', 'getaddrinfo EAI_AGAIN discord.com', '[Error: 30130000:error:0A000410:SSL'].includes(error.message)) return; //console.error(error); - const channel = client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel | null; - // vvv Oh yes, that looks really hot. - channel?.send({embeds: [new client.embed().setColor('#560000').setTitle('Error caught!').setFooter({text: 'Error type: ' + type}).setDescription(`**Error:**\n\`\`\`${error.message}\`\`\`**Stack:**\n\`\`\`${`${error.stack}`.slice(0, 2500)}\`\`\``)]}) + (client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel | null)?.send({embeds: [new client.embed().setColor('#560000').setTitle('Error caught!').setFooter({text: 'Error type: ' + type}).setDescription(`**Error:**\n\`\`\`${error.message}\`\`\`**Stack:**\n\`\`\`${`${error.stack}`.slice(0, 2500)}\`\`\``)]}) } process.on('unhandledRejection', (error: Error)=>DZ(error, 'unhandledRejection')); process.on('uncaughtException', (error: Error)=>DZ(error, 'uncaughtException')); @@ -72,16 +70,14 @@ setInterval(async()=>{ // Event loop for punishments and daily msgs setInterval(async()=>{ const now = Date.now(); - const lrsStart = client.config.LRSstart; const punishments = await client.punishments._content.find({}); punishments.filter(x=>x.endTime && x.endTime<= now && !x.expired).forEach(async punishment=>{ console.log(client.logTime(), `${punishment.member}\'s ${punishment.type} should expire now`); - const unpunishResult = await client.punishments.removePunishment(punishment._id, client.user.id, 'Time\'s up!'); - console.log(client.logTime(), unpunishResult); + console.log(client.logTime(), await client.punishments.removePunishment(punishment._id, client.user.id, 'Time\'s up!')); }); - const formattedDate = Math.floor((now - lrsStart)/1000/60/60/24); + const formattedDate = Math.floor((now - client.config.LRSstart)/1000/60/60/24); const dailyMsgs = JSON.parse(readFileSync('./src/database/dailyMsgs.json', {encoding: 'utf8'})) if (!dailyMsgs.some((x:Array)=>x[0] === formattedDate)){ let total = (await client.userLevels._content.find({})).reduce((a,b)=>a + b.messages, 0); // sum of all users