finished automod
diff --git a/src/commands/settings/automod.ts b/src/commands/settings/automod.ts
index a7b6dbc..8e006b0 100644
--- a/src/commands/settings/automod.ts
+++ b/src/commands/settings/automod.ts
@@ -1,10 +1,34 @@
 import type Discord from "discord.js";
-import { ActionRowBuilder, AnyComponent, AnyComponentBuilder, AnySelectMenuInteraction, APIMessageComponentEmoji, ButtonBuilder, ButtonInteraction, ButtonStyle, ChannelSelectMenuBuilder, ChannelSelectMenuInteraction, CommandInteraction, Guild, GuildMember, GuildTextBasedChannel, MentionableSelectMenuBuilder, Message, Role, RoleSelectMenuBuilder, RoleSelectMenuInteraction, SelectMenuBuilder, StringSelectMenuBuilder, StringSelectMenuInteraction, StringSelectMenuOptionBuilder, UserSelectMenuBuilder, UserSelectMenuInteraction } from "discord.js";
+import { ActionRowBuilder,
+    AnySelectMenuInteraction,
+    APIMessageComponentEmoji,
+    ButtonBuilder,
+    ButtonInteraction,
+    ButtonStyle,
+    ChannelSelectMenuBuilder,
+    ChannelSelectMenuInteraction,
+    CommandInteraction,
+    Interaction,
+    Message,
+    MessageComponentInteraction,
+    ModalBuilder,
+    ModalSubmitInteraction,
+    RoleSelectMenuBuilder,
+    RoleSelectMenuInteraction,
+    StringSelectMenuBuilder,
+    StringSelectMenuInteraction,
+    StringSelectMenuOptionBuilder,
+    TextInputBuilder,
+    TextInputStyle,
+    UserSelectMenuBuilder,
+    UserSelectMenuInteraction
+} from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "discord.js";
 import { LoadingEmbed } from "../../utils/defaults.js";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import client from "../../utils/client.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
+import { modalInteractionCollector } from "../../utils/dualCollector.js";
 
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
@@ -75,7 +99,7 @@
 
         let i: AnySelectMenuInteraction | ButtonInteraction;
         try {
-            i = await interaction.channel!.awaitMessageComponent({filter: i => i.user.id === interaction.user.id, time: 300000});
+            i = await m.awaitMessageComponent({filter: i => i.user.id === interaction.user.id, time: 300000});
         } catch(e) {
             closed = true;
             break;
@@ -177,7 +201,152 @@
 }> => {
     let closed = false;
     do {
-        closed = true;
+        const buttons = new ActionRowBuilder<ButtonBuilder>()
+            .addComponents(
+                new ButtonBuilder()
+                    .setCustomId("back")
+                    .setLabel("Back")
+                    .setStyle(ButtonStyle.Secondary)
+                    .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
+                new ButtonBuilder()
+                    .setCustomId("enabled")
+                    .setLabel("Enabled")
+                    .setStyle(current.enabled ? ButtonStyle.Success : ButtonStyle.Danger)
+                    .setEmoji(emojiFromBoolean(current.enabled, "id") as APIMessageComponentEmoji),
+            );
+
+        const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
+            .addComponents(
+                new StringSelectMenuBuilder()
+                    .setCustomId("edit")
+                    .setPlaceholder("Edit... ")
+                    .addOptions(
+                        new StringSelectMenuOptionBuilder()
+                            .setLabel("Words")
+                            .setDescription("Edit your list of words to filter")
+                            .setValue("words"),
+                        new StringSelectMenuOptionBuilder()
+                            .setLabel("Allowed Users")
+                            .setDescription("Users who will be unaffected by the word filter")
+                            .setValue("allowedUsers"),
+                        new StringSelectMenuOptionBuilder()
+                            .setLabel("Allowed Roles")
+                            .setDescription("Roles that will be unaffected by the word filter")
+                            .setValue("allowedRoles"),
+                        new StringSelectMenuOptionBuilder()
+                            .setLabel("Allowed Channels")
+                            .setDescription("Channels where the word filter will not apply")
+                            .setValue("allowedChannels")
+                    )
+                    .setDisabled(!current.enabled)
+            );
+
+        const embed = new EmojiEmbed()
+            .setTitle("Word Filters")
+            .setDescription(
+                `${emojiFromBoolean(current.enabled)} **Enabled**\n` +
+                `**Strict Words:** ${listToAndMore(current.words.strict, 5)}\n` +
+                `**Loose Words:** ${listToAndMore(current.words.loose, 5)}\n\n` +
+                `**Users:** ` + listToAndMore(current.allowed.users.map(user => `<@${user}>`), 5) + `\n` +
+                `**Roles:** ` + listToAndMore(current.allowed.roles.map(role => `<@&${role}>`), 5) + `\n` +
+                `**Channels:** ` + listToAndMore(current.allowed.channels.map(channel => `<#${channel}>`), 5)
+            )
+            .setStatus("Success")
+            .setEmoji("GUILD.SETTINGS.GREEN")
+
+        await interaction.editReply({embeds: [embed], components: [selectMenu, buttons]});
+
+        let i: ButtonInteraction | StringSelectMenuInteraction;
+        try {
+            i = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction | StringSelectMenuInteraction;
+        } catch (e) {
+            closed = true;
+            break;
+        }
+
+        if(i.isButton()) {
+            await i.deferUpdate();
+            switch(i.customId) {
+                case "back":
+                    closed = true;
+                    break;
+                case "enabled":
+                    current.enabled = !current.enabled;
+                    break;
+            }
+        } else {
+            switch(i.values[0]) {
+                case "words":
+                    await interaction.editReply({embeds: [new EmojiEmbed()
+                        .setTitle("Word Filter")
+                        .setDescription("Modal opened. If you can't see it, click back and try again.")
+                        .setStatus("Success")
+                        .setEmoji("GUILD.SETTINGS.GREEN")
+                    ], components: [new ActionRowBuilder<ButtonBuilder>().addComponents(new ButtonBuilder()
+                        .setLabel("Back")
+                        .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+                        .setStyle(ButtonStyle.Primary)
+                        .setCustomId("back")
+                    )]})
+                    const modal = new ModalBuilder()
+                        .setTitle("Word Filter")
+                        .setCustomId("wordFilter")
+                        .addComponents(
+                            new ActionRowBuilder<TextInputBuilder>()
+                                .addComponents(
+                                    new TextInputBuilder()
+                                        .setCustomId("wordStrict")
+                                        .setLabel("Strict Words")
+                                        .setPlaceholder("Matches anywhere in the message, including surrounded by other characters")
+                                        .setValue(current.words.strict.join(", ") ?? "")
+                                        .setStyle(TextInputStyle.Paragraph)
+                                        .setRequired(false)
+                                ),
+                            new ActionRowBuilder<TextInputBuilder>()
+                                .addComponents(
+                                    new TextInputBuilder()
+                                        .setCustomId("wordLoose")
+                                        .setLabel("Loose Words")
+                                        .setPlaceholder("Matches only if the word is by itself, surrounded by spaces or punctuation")
+                                        .setValue(current.words.loose.join(", ") ?? "")
+                                        .setStyle(TextInputStyle.Paragraph)
+                                        .setRequired(false)
+                                )
+                        )
+
+                    await i.showModal(modal);
+                    let out;
+                    try {
+                        out = await modalInteractionCollector(
+                            m,
+                            (m: Interaction) =>
+                                (m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId,
+                            (m) => m.customId === "back"
+                        );
+                    } catch (e) {
+                        break;
+                    }
+                    if (!out) break;
+                    if(out.isButton()) break;
+                    current.words.strict = out.fields.getTextInputValue("wordStrict")
+                        .split(",").map(s => s.trim()).filter(s => s.length > 0);
+                    current.words.loose = out.fields.getTextInputValue("wordLoose")
+                        .split(",").map(s => s.trim()).filter(s => s.length > 0);
+                    break;
+                case "allowedUsers":
+                    await i.deferUpdate();
+                    current.allowed.users = await toSelectMenu(interaction, m, current.allowed.users, "member", "Word Filter");
+                    break;
+                case "allowedRoles":
+                    await i.deferUpdate();
+                    current.allowed.roles = await toSelectMenu(interaction, m, current.allowed.roles, "role", "Word Filter");
+                    break;
+                case "allowedChannels":
+                    await i.deferUpdate();
+                    current.allowed.channels = await toSelectMenu(interaction, m, current.allowed.channels, "channel", "Word Filter");
+                    break;
+            }
+        }
     } while(!closed);
     return current;
 }
@@ -231,15 +400,15 @@
             .setDescription(
                 "Automatically deletes invites sent by users (outside of staff members and self promotion channels)" + `\n\n` +
                 `${emojiFromBoolean(current.enabled)} **${current.enabled ? "Enabled" : "Disabled"}**\n\n` +
-                `**Users:** ` + listToAndMore(current.allowed.users.map(user => `> <@${user}>`), 5) + `\n` +
-                `**Roles:** ` + listToAndMore(current.allowed.roles.map(role => `> <@&${role}>`), 5) + `\n` +
-                `**Channels:** ` + listToAndMore(current.allowed.channels.map(channel => `> <#${channel}>`), 5)
+                `**Users:** ` + listToAndMore(current.allowed.users.map(user => `<@${user}>`), 5) + `\n` +
+                `**Roles:** ` + listToAndMore(current.allowed.roles.map(role => `<@&${role}>`), 5) + `\n` +
+                `**Channels:** ` + listToAndMore(current.allowed.channels.map(channel => `<#${channel}>`), 5)
             )
             .setStatus("Success")
             .setEmoji("GUILD.SETTINGS.GREEN")
 
 
-        await interaction.editReply({embeds: [embed], components: [buttons, menu]});
+        await interaction.editReply({embeds: [embed], components: [menu, buttons]});
 
         let i: ButtonInteraction | StringSelectMenuInteraction;
         try {
@@ -301,7 +470,172 @@
     let closed = false;
 
     do {
-        closed = true;
+
+        const buttons = new ActionRowBuilder<ButtonBuilder>()
+            .addComponents(
+                new ButtonBuilder()
+                    .setCustomId("back")
+                    .setLabel("Back")
+                    .setStyle(ButtonStyle.Secondary)
+                    .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
+                new ButtonBuilder()
+                    .setCustomId("everyone")
+                    .setLabel(current.everyone ? "Everyone" : "No one")
+                    .setStyle(current.everyone ? ButtonStyle.Success : ButtonStyle.Danger)
+                    .setEmoji(emojiFromBoolean(current.everyone, "id") as APIMessageComponentEmoji),
+                new ButtonBuilder()
+                    .setCustomId("roles")
+                    .setLabel(current.roles ? "Roles" : "No roles")
+                    .setStyle(current.roles ? ButtonStyle.Success : ButtonStyle.Danger)
+                    .setEmoji(emojiFromBoolean(current.roles, "id") as APIMessageComponentEmoji)
+            );
+        const menu = new ActionRowBuilder<StringSelectMenuBuilder>()
+            .addComponents(
+                new StringSelectMenuBuilder()
+                    .setCustomId("toEdit")
+                    .setPlaceholder("Edit mention settings")
+                    .addOptions(
+                        new StringSelectMenuOptionBuilder()
+                            .setLabel("Mass Mention Amount")
+                            .setDescription("The amount of mentions before the bot will delete the message")
+                            .setValue("mass"),
+                        new StringSelectMenuOptionBuilder()
+                            .setLabel("Roles")
+                            .setDescription("Roles that are able to be mentioned")
+                            .setValue("roles"),
+                    )
+            )
+
+        const allowedMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
+            .addComponents(
+                new StringSelectMenuBuilder()
+                    .setCustomId("allowed")
+                    .setPlaceholder("Edit exceptions")
+                    .addOptions(
+                        new StringSelectMenuOptionBuilder()
+                                .setLabel("Users")
+                                .setDescription("Users that are unaffected by the mention filter")
+                                .setValue("users"),
+                            new StringSelectMenuOptionBuilder()
+                                .setLabel("Roles")
+                                .setDescription("Roles that are unaffected by the mention filter")
+                                .setValue("roles"),
+                            new StringSelectMenuOptionBuilder()
+                                .setLabel("Channels")
+                                .setDescription("Channels where anyone is unaffected by the mention filter")
+                                .setValue("channels")
+                    )
+            )
+
+        const embed = new EmojiEmbed()
+            .setTitle("Mention Settings")
+            .setDescription(
+                `Log when members mention:\n` +
+                `${emojiFromBoolean(true)} **${current.mass}+ members** in one message\n` +
+                `${emojiFromBoolean(current.everyone)} **Everyone**\n` +
+                `${emojiFromBoolean(current.roles)} **Roles**\n` +
+                (current.allowed.rolesToMention.length > 0 ? `> *Except for ${listToAndMore(current.allowed.rolesToMention.map(r => `<@&${r}>`), 3)}*\n` : "") +
+                "\n" +
+                `Except if...\n` +
+                `> ${current.allowed.users.length > 0 ? `Member is: ${listToAndMore(current.allowed.users.map(u => `<@${u}>`), 3)}\n` : ""}` +
+                `> ${current.allowed.roles.length > 0 ? `Member has role: ${listToAndMore(current.allowed.roles.map(r => `<@&${r}>`), 3)}\n` : ""}` +
+                `> ${current.allowed.channels.length > 0 ? `In channel: ${listToAndMore(current.allowed.channels.map(c => `<#${c}>`), 3)}\n` : ""}`
+            )
+            .setStatus("Success")
+            .setEmoji("GUILD.SETTINGS.GREEN")
+
+        await interaction.editReply({embeds: [embed], components: [menu, allowedMenu, buttons]});
+
+        let i: ButtonInteraction | StringSelectMenuInteraction;
+        try {
+            i = await m.awaitMessageComponent({filter: (i) => interaction.user.id === i.user.id && i.message.id === m.id, time: 300000}) as ButtonInteraction | StringSelectMenuInteraction;
+        } catch (e) {
+            closed = true;
+            break;
+        }
+
+        if(i.isButton()) {
+            await i.deferUpdate();
+            switch (i.customId) {
+                case "back":
+                    closed = true;
+                    break;
+                case "everyone":
+                    current.everyone = !current.everyone;
+                    break;
+                case "roles":
+                    current.roles = !current.roles;
+                    break;
+            }
+        } else {
+            switch (i.customId) {
+                case "toEdit":
+                    switch (i.values[0]) {
+                        case "mass":
+                            await interaction.editReply({embeds: [new EmojiEmbed()
+                                .setTitle("Word Filter")
+                                .setDescription("Modal opened. If you can't see it, click back and try again.")
+                                .setStatus("Success")
+                                .setEmoji("GUILD.SETTINGS.GREEN")
+                            ], components: [new ActionRowBuilder<ButtonBuilder>().addComponents(new ButtonBuilder()
+                                .setLabel("Back")
+                                .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+                                .setStyle(ButtonStyle.Primary)
+                                .setCustomId("back")
+                            )]})
+                            const modal = new ModalBuilder()
+                                .setTitle("Mass Mention Amount")
+                                .setCustomId("mass")
+                                .addComponents(
+                                    new ActionRowBuilder<TextInputBuilder>()
+                                        .addComponents(
+                                            new TextInputBuilder()
+                                                .setCustomId("mass")
+                                                .setPlaceholder("Amount")
+                                                .setMinLength(1)
+                                                .setMaxLength(3)
+                                                .setStyle(TextInputStyle.Short)
+                                        )
+                                )
+                            await i.showModal(modal);
+                            let out;
+                            try {
+                                out = await modalInteractionCollector(
+                                    m,
+                                    (m: Interaction) =>
+                                        (m as MessageComponentInteraction | ModalSubmitInteraction).channelId === interaction.channelId,
+                                    (m) => m.customId === "back"
+                                );
+                            } catch (e) {
+                                break;
+                            }
+                            if (!out) break;
+                            if(out.isButton()) break;
+                            current.mass = parseInt(out.fields.getTextInputValue("mass"));
+                            break;
+                        case "roles":
+                            await i.deferUpdate();
+                            current.allowed.rolesToMention = await toSelectMenu(interaction, m, current.allowed.rolesToMention, "role", "Mention Settings");
+                            break;
+                    }
+                    break;
+                case "allowed":
+                    await i.deferUpdate();
+                    switch (i.values[0]) {
+                        case "users":
+                            current.allowed.users = await toSelectMenu(interaction, m, current.allowed.users, "member", "Mention Settings");
+                            break;
+                        case "roles":
+                            current.allowed.roles = await toSelectMenu(interaction, m, current.allowed.roles, "role", "Mention Settings");
+                            break;
+                        case "channels":
+                            current.allowed.channels = await toSelectMenu(interaction, m, current.allowed.channels, "channel", "Mention Settings");
+                            break;
+                    }
+                    break;
+            }
+        }
+
     } while(!closed);
     return current
 }
diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts
index 9563a33..65e1422 100644
--- a/src/events/messageDelete.ts
+++ b/src/events/messageDelete.ts
@@ -6,7 +6,7 @@
 export async function callback(client: NucleusClient, message: Message) {
     if (message.author.id === client.user!.id) return;
     if (message.author.bot) return;
-    if (client.noLog.includes(`${message.id}/${message.channel.id}/${message.id}`)) return;
+    if (client.noLog.includes(`${message.guild!.id}/${message.channel.id}/${message.id}`)) return;
     const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
     const auditLog = (await getAuditLog(message.guild!, AuditLogEvent.MemberBanAdd))
         .filter((entry: GuildAuditLogsEntry) => (entry.target! as User).id === message.author.id)[0];
diff --git a/src/reflex/scanners.ts b/src/reflex/scanners.ts
index c8d59f0..c55e463 100644
--- a/src/reflex/scanners.ts
+++ b/src/reflex/scanners.ts
@@ -9,19 +9,18 @@
 
 interface NSFWSchema {
     nsfw: boolean;
+    errored?: boolean;
 }
 interface MalwareSchema {
     safe: boolean;
+    errored?: boolean;
 }
 
 export async function testNSFW(link: string): Promise<NSFWSchema> {
     const [p, hash] = await saveAttachment(link);
-    console.log("Checking an image")
     let alreadyHaveCheck = await client.database.scanCache.read(hash)
     if(alreadyHaveCheck) return { nsfw: alreadyHaveCheck.data };
-    console.log("Was not in db")
     const data = new FormData();
-    console.log(link);
     data.append("file", createReadStream(p));
     const result = await fetch("https://unscan.p.rapidapi.com/", {
         method: "POST",
@@ -31,13 +30,14 @@
         },
         body: data
     })
-        .then((response) => response.json() as Promise<NSFWSchema>)
+        .then((response) => response.status === 200 ? response.json() as Promise<NSFWSchema> : { nsfw: false, errored: true })
         .catch((err) => {
             console.error(err);
-            return { nsfw: false };
+            return { nsfw: false, errored: true };
         });
-    console.log(result);
-    client.database.scanCache.write(hash, result.nsfw);
+    if(!result.errored) {
+        client.database.scanCache.write(hash, result.nsfw);
+    }
     return { nsfw: result.nsfw };
 }
 
@@ -48,7 +48,6 @@
     const data = new URLSearchParams();
     let f = createReadStream(p);
     data.append("file", f.read(fs.statSync(p).size));
-    console.log(link);
     const result = await fetch("https://unscan.p.rapidapi.com/malware", {
         method: "POST",
         headers: {
@@ -57,18 +56,18 @@
         },
         body: data
     })
-        .then((response) => response.json() as Promise<MalwareSchema>)
+        .then((response) => response.status === 200 ? response.json() as Promise<MalwareSchema> : { safe: true, errored: true })
         .catch((err) => {
             console.error(err);
-            return { safe: true };
+            return { safe: true, errored: true };
         });
-    console.log(result);
-    client.database.scanCache.write(hash, result.safe);
+    if (!result.errored) {
+        client.database.scanCache.write(hash, result.safe);
+    }
     return { safe: result.safe };
 }
 
 export async function testLink(link: string): Promise<{ safe: boolean; tags: string[] }> {
-    console.log(link);
     let alreadyHaveCheck = await client.database.scanCache.read(link)
     if(alreadyHaveCheck) return { safe: alreadyHaveCheck.data, tags: [] };
     const scanned: { safe?: boolean; tags?: string[] } = await fetch("https://unscan.p.rapidapi.com/link", {
@@ -84,7 +83,6 @@
             console.error(err);
             return { safe: true, tags: [] };
         });
-    console.log(scanned);
     client.database.scanCache.write(link, scanned.safe ?? true, []);
     return {
         safe: scanned.safe ?? true,
@@ -93,10 +91,11 @@
 }
 
 export async function saveAttachment(link: string): Promise<[string, string]> {
-    const image = (await fetch(link)).arrayBuffer().toString();
+    const image = await (await fetch(link)).arrayBuffer()
     const fileName = generateFileName(link.split("/").pop()!.split(".").pop()!);
-    writeFileSync(fileName, image, "base64");
-    return [fileName, createHash('sha512').update(image, 'base64').digest('base64')];
+    const enc = new TextDecoder("utf-8");
+    writeFileSync(fileName, new DataView(image), "base64");
+    return [fileName, createHash('sha512').update(enc.decode(image), 'base64').digest('base64')];
 }
 
 const linkTypes = {
diff --git a/src/utils/log.ts b/src/utils/log.ts
index 4eff4e2..c5c7e06 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -10,7 +10,7 @@
 
 export const Logger = {
     renderUser(user: Discord.User | string) {
-        if (typeof user === "string") return `${user} [<@${user}>]`;
+        if (typeof user === "string") user = client.users.cache.get(user) as Discord.User;
         return `${user.username} [<@${user.id}>]`;
     },
     renderTime(t: number) {
@@ -55,7 +55,6 @@
         const config = await client.database.guilds.read(log.hidden.guild);
         if (!config.logging.logs.enabled) return;
         if (!toHexArray(config.logging.logs.toLog).includes(log.meta.calculateType)) {
-            console.log("Not logging this type of event");
             return;
         }
         if (config.logging.logs.channel) {