loads of bug fixes
diff --git a/src/events/channelDelete.ts b/src/events/channelDelete.ts
index 5c7139a..ffe3eae 100644
--- a/src/events/channelDelete.ts
+++ b/src/events/channelDelete.ts
@@ -39,7 +39,7 @@
             }
         }
         let list = {
-            channelIid: entry(channel.id, `\`${channel.id}\``),
+            channelId: entry(channel.id, `\`${channel.id}\``),
             name: entry(channel.id, `${channel.name}`),
             topic: null,
             type: entry(channel.type, readableType),
diff --git a/src/events/commandError.ts b/src/events/commandError.ts
index 8edb480..6d3672e 100644
--- a/src/events/commandError.ts
+++ b/src/events/commandError.ts
@@ -5,7 +5,7 @@
 export async function callback(client, interaction, error) {
     if (interaction.replied || interaction.deferred) {
         await interaction.followUp({embeds: [new EmojiEmbed()
-            .setTitle("Something went wrong")
+            .setTitle("Something went")
             .setDescription(error.message ?? error.toString())
             .setStatus("Danger")
             .setEmoji("CONTROL.BLOCKCROSS")
diff --git a/src/events/guildBanAdd.ts b/src/events/guildBanAdd.ts
index 05b98ed..64a1604 100644
--- a/src/events/guildBanAdd.ts
+++ b/src/events/guildBanAdd.ts
@@ -1,5 +1,5 @@
-import { purgeByUser } from '../automations/tickets/delete.js';
-import { callback as statsChannelRemove } from '../automations/statsChannelRemove.js';
+import { purgeByUser } from '../actions/tickets/delete.js';
+import { callback as statsChannelRemove } from '../reflex/statsChannelRemove.js';
 
 export const event = 'guildBanAdd';
 
diff --git a/src/events/guildBanRemove.ts b/src/events/guildBanRemove.ts
index 85dc2af..a6d1c14 100644
--- a/src/events/guildBanRemove.ts
+++ b/src/events/guildBanRemove.ts
@@ -1,6 +1,6 @@
 import humanizeDuration from 'humanize-duration';
-import { purgeByUser } from '../automations/tickets/delete.js';
-import { callback as statsChannelRemove } from '../automations/statsChannelRemove.js';
+import { purgeByUser } from '../actions/tickets/delete.js';
+import { callback as statsChannelRemove } from '../reflex/statsChannelRemove.js';
 
 export const event = 'guildBanRemove';
 
diff --git a/src/events/guildCreate.ts b/src/events/guildCreate.ts
index 10986a5..413e5fb 100644
--- a/src/events/guildCreate.ts
+++ b/src/events/guildCreate.ts
@@ -1,7 +1,7 @@
 import { MessageActionRow, MessageButton } from "discord.js";
 import EmojiEmbed from "../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../utils/getEmojiByName.js";
-import guide from "../automations/guide.js";
+import guide from "../reflex/guide.js";
 
 export const event = 'guildCreate';
 
diff --git a/src/events/guildMemberUpdate.ts b/src/events/guildMemberUpdate.ts
index dab89fa..e68aee4 100644
--- a/src/events/guildMemberUpdate.ts
+++ b/src/events/guildMemberUpdate.ts
@@ -1,15 +1,12 @@
-import { callback as statsChannelAdd } from '../automations/statsChannelAdd.js';
-import { callback as welcome } from '../automations/welcome.js';
-import log from '../utils/log.js';
 export const event = 'guildMemberUpdate'
 
 export async function callback(client, before, after) {
     try {
         const { log, NucleusColors, entry, renderUser, renderDelta, getAuditLog } = after.client.logger
+        let auditLog = await getAuditLog(after.guild, 'MEMBER_UPDATE');
+        let audit = auditLog.entries.filter(entry => entry.target.id == after.id).first();
+        if (audit.executor.id == client.user.id) return;
         if (before.nickname != after.nickname) {
-            let auditLog = await getAuditLog(after.guild, 'MEMBER_UPDATE');
-            let audit = auditLog.entries.filter(entry => entry.target.id == after.id).first();
-            if (audit.executor.id == client.user.id) return;
             try { await client.database.history.create(
                 "nickname", after.guild.id, after.user, audit.executor,
                 null, before.nickname || before.user.username, after.nickname || after.user.username) } catch {}
@@ -24,16 +21,74 @@
                 },
                 list: {
                     memberId: entry(after.id, `\`${after.id}\``),
+                    name: entry(after.user.id, renderUser(after.user)),
                     before: entry(before.nickname, before.nickname ? before.nickname : '*None*'),
                     after: entry(after.nickname, after.nickname ? after.nickname : '*None*'),
-                    updated: entry(new Date().getTime(), renderDelta(new Date().getTime())),
-                    updatedBy: entry(audit.executor.id, renderUser(audit.executor))
+                    changed: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+                    changedBy: entry(audit.executor.id, renderUser(audit.executor))
                 },
                 hidden: {
                     guild: after.guild.id
                 }
             }
             log(data);
+        } else if (before.communicationDisabledUntilTimestamp < new Date().getTime() && after.communicationDisabledUntil > new Date().getTime()) {
+            try { await client.database.history.create(
+                "mute", after.guild.id, after.user, audit.executor, audit.reason, null, null, null
+            )} catch {}
+            let data = {
+                meta: {
+                    type: 'memberMute',
+                    displayName: 'Muted',
+                    calculateType: 'guildMemberPunish',
+                    color: NucleusColors.yellow,
+                    emoji: "PUNISH.MUTE.YELLOW",
+                    timestamp: new Date().getTime()
+                },
+                list: {
+                    memberId: entry(after.id, `\`${after.id}\``),
+                    name: entry(after.user.id, renderUser(after.user)),
+                    mutedUntil: entry(after.communicationDisabledUntilTimestamp, renderDelta(after.communicationDisabledUntilTimestamp)),
+                    muted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+                    mutedBy: entry(audit.executor.id, renderUser(audit.executor)),
+                    reason: entry(audit.reason, audit.reason ? audit.reason : '\n> *No reason provided*')
+                },
+                hidden: {
+                    guild: after.guild.id
+                }
+            }
+            log(data);
+            client.database.eventScheduler.schedule("naturalUnmute", after.communicationDisabledUntil,
+                {guild: after.guild.id, user: after.id, expires: after.communicationDisabledUntilTimestamp}
+            );
+        } else if (
+            after.communicationDisabledUntil === null && before.communicationDisabledUntilTimestamp !== null &&
+            new Date().getTime() >= audit.createdTimestamp
+        ) {
+            try { await client.database.history.create(
+                "unmute", after.guild.id, after.user, audit.executor, null, null, null, null
+            )} catch {}
+            let data = {
+                meta: {
+                    type: 'memberUnmute',
+                    displayName: 'Unmuted',
+                    calculateType: 'guildMemberPunish',
+                    color: NucleusColors.green,
+                    emoji: "PUNISH.MUTE.GREEN",
+                    timestamp: new Date().getTime()
+                },
+                list: {
+                    memberId: entry(after.id, `\`${after.id}\``),
+                    name: entry(after.user.id, renderUser(after.user)),
+                    unmuted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+                    unmutedBy: entry(audit.executor.id, renderUser(audit.executor))
+                },
+                hidden: {
+                    guild: after.guild.id
+                }
+            }
+            log(data);
+            client.database.eventScheduler.cancel("naturalUnmute", {guild: after.guild.id, user: after.id, expires: before.communicationDisabledUntilTimestamp});
         }
     } catch (e) { console.log(e) }
 }
diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts
index 3470450..1fd1e1f 100644
--- a/src/events/interactionCreate.ts
+++ b/src/events/interactionCreate.ts
@@ -1,7 +1,8 @@
-import { callback as roleMenu } from "../automations/roleMenu.js"
-import verify from "../automations/verify.js";
-import create from "../automations/tickets/create.js";
-import close from "../automations/tickets/delete.js";
+import { callback as roleMenu } from "../actions/roleMenu.js"
+import verify from "../reflex/verify.js";
+import create from "../actions/tickets/create.js";
+import close from "../actions/tickets/delete.js";
+import createTranscript from "../premium/createTranscript.js";
 
 export const event = 'interactionCreate';
 
@@ -11,6 +12,7 @@
         if (interaction.customId === "verifybutton") return verify(interaction)
         if (interaction.customId === "createticket") return create(interaction)
         if (interaction.customId === "closeticket") return close(interaction)
+        if (interaction.customId === "createtranscript") return createTranscript(interaction)
     } else if (interaction.componentType === "MESSAGE_COMPONENT") {
         console.table(interaction)
     }
diff --git a/src/events/memberJoin.ts b/src/events/memberJoin.ts
index 2031b12..b1c2700 100644
--- a/src/events/memberJoin.ts
+++ b/src/events/memberJoin.ts
@@ -1,5 +1,5 @@
-import { callback as statsChannelAdd } from '../automations/statsChannelAdd.js';
-import { callback as welcome } from '../automations/welcome.js';
+import { callback as statsChannelAdd } from '../reflex/statsChannelAdd.js';
+import { callback as welcome } from '../reflex/welcome.js';
 import log from '../utils/log.js';
 import client from '../utils/client.js';
 
diff --git a/src/events/memberLeave.ts b/src/events/memberLeave.ts
index b9d6e84..592a630 100644
--- a/src/events/memberLeave.ts
+++ b/src/events/memberLeave.ts
@@ -1,6 +1,6 @@
 import humanizeDuration from 'humanize-duration';
-import { purgeByUser } from '../automations/tickets/delete.js';
-import { callback as statsChannelRemove } from '../automations/statsChannelRemove.js';
+import { purgeByUser } from '../actions/tickets/delete.js';
+import { callback as statsChannelRemove } from '../reflex/statsChannelRemove.js';
 
 export const event = 'guildMemberRemove'
 
diff --git a/src/events/messageChecks.ts b/src/events/messageChecks.ts
deleted file mode 100644
index 2755ff1..0000000
--- a/src/events/messageChecks.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { LinkCheck, MalwareCheck, NSFWCheck, SizeCheck, TestString, TestImage } from '../automations/unscan.js'
-import { Message } from 'discord.js'
-import client from '../utils/client.js'
-
-export const event = 'messageCreate'
-
-export async function callback(client, message) {
-    const { log, NucleusColors, entry, renderUser } = client.logger
-    if (message.author.bot) return
-    if (message.channel.type === 'dm') return
-
-    let content = message.content.toLowerCase() || ''
-    let config = await client.memory.readGuildInfo(message.guild.id);
-
-    if (config.filters.invite.enabled) {
-        if (!config.filters.invite.allowed.users.includes(message.author.id) ||
-            !config.filters.invite.allowed.channels.includes(message.channel.id) ||
-            !message.author.roles.cache.some(role => config.filters.invite.allowed.roles.includes(role.id))
-        ) {
-            if ((/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(content))) {
-                return message.delete();
-            }
-        }
-    }
-
-    let attachments = message.attachments.map(element => element)
-    attachments = [...attachments, ...content.match(
-        /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi
-    ) ?? []].filter(element => (element.url ? element.url : element))
-    if (attachments.length > 0) {
-        attachments.forEach(async element => {
-            if(!message) return;
-            let url = element.url ? element.url : element
-            if (url != undefined) {
-                if(/\.+(webp|png|jpg|jpeg|bmp)/.test(url)) {
-                    if (config.filters.images.NSFW && !message.channel.nsfw) {
-                        if (await NSFWCheck(url)) {
-                            return await message.delete()
-                        }
-                    }
-                    if (config.filters.images.size) {
-                        if(!url.match(/\.+(webp|png|jpg)$/gi)) return
-                        if(!await SizeCheck(element)) {
-                            return await message.delete()
-                        }
-                    }
-                }
-                if (config.filters.malware) {
-                    if (!MalwareCheck(url)) {
-                        return await message.delete()
-                    }
-                }
-            }
-        });
-    }
-    if(!message) return;
-
-    if (await LinkCheck(message)) {
-        return await message.delete()
-    }
-
-    if (config.filters.wordFilter.enabled) {
-        let check = TestString(content, config.filters.wordFilter.words.loose, config.filters.wordFilter.words.strict)
-        if(check !== null) {
-            return await message.delete()
-        }
-    }
-
-    if (!config.filters.pings.allowed.users.includes(message.author.id) ||
-        !config.filters.pings.allowed.channels.includes(message.channel.id) ||
-        !message.author.roles.cache.some(role => config.filters.pings.allowed.roles.includes(role.id))
-    ) {
-        if (config.filters.pings.everyone && message.mentions.everyone) {
-            return message.delete();
-        }
-        if (config.filters.pings.roles) {
-            for(let role of message.mentions.roles) {
-                if(!message) return;
-                if (!config.filters.pings.allowed.roles.includes(role.id)) {
-                    return message.delete();
-                }
-            }
-        }
-        if(!message) return;
-        if (message.mentions.users.size >= config.filters.pings.mass && config.filters.pings.mass) {
-            return message.delete();
-        }
-    }
-}
diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts
index f0fbb57..2263d51 100644
--- a/src/events/messageDelete.ts
+++ b/src/events/messageDelete.ts
@@ -3,6 +3,7 @@
 export async function callback(client, message) {
     try {
         if (message.author.id == client.user.id) return;
+        if (client.noLog.includes(`${message.guild.id}/${message.channel.id}/${message.id}`)) return;
         const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta, renderChannel } = message.channel.client.logger
         let auditLog = await getAuditLog(message.guild, 'MEMBER_BAN_ADD')
         let audit = auditLog.entries.filter(entry => entry.target.id == message.author.id).first();
@@ -11,7 +12,11 @@
         }
         message.reference = message.reference || {}
         let content = message.cleanContent
+        content.replace(`\``, `\\\``)
         if (content.length > 256) content = content.substring(0, 253) + '...'
+        let attachmentJump = ""
+        let config = (await client.database.guilds.read(message.guild.id)).logging.attachments.saved[message.channel.id + message.id];
+        if (config) { attachmentJump = ` [[View attachments]](${config})` }
         let data = {
             meta: {
                 type: 'messageDelete',
@@ -30,7 +35,7 @@
                 sentIn: entry(message.channel.id, renderChannel(message.channel)),
                 deleted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                 mentions: message.mentions.users.size,
-                attachments: message.attachments.size,
+                attachments: entry(message.attachments.size, message.attachments.size + attachmentJump),
                 repliedTo: entry(
                     message.reference.messageId || null,
                     message.reference.messageId ? `[[Jump to message]](https://discord.com/channels/${message.guild.id}/${message.channel.id}/${message.reference.messageId})` : "None"
@@ -41,5 +46,5 @@
             }
         }
         log(data);
-    } catch {}
+    } catch(e) { console.log(e) }
 }
diff --git a/src/events/messageEdit.ts b/src/events/messageEdit.ts
index 3502963..5e63797 100644
--- a/src/events/messageEdit.ts
+++ b/src/events/messageEdit.ts
@@ -7,6 +7,9 @@
         newMessage.reference = newMessage.reference || {}
         let newContent = newMessage.cleanContent.replaceAll("`", "‘")
         let oldContent = oldMessage.cleanContent.replaceAll("`", "‘")
+        let attachmentJump = "";
+        let config = (await client.database.guilds.read(newMessage.guild.id)).logging.attachments.saved[newMessage.channel.id + newMessage.id];
+        if (config) { attachmentJump = ` [[View attachments]](${config})` }
         if (newContent == oldContent) {
             if (!oldMessage.flags.has("CROSSPOSTED") && newMessage.flags.has("CROSSPOSTED")) {
                 let data = {
@@ -28,16 +31,19 @@
                         sent: entry(new Date(newMessage.createdTimestamp), renderDelta(new Date(newMessage.createdTimestamp))),
                         published: entry(new Date(newMessage.editedTimestamp), renderDelta(new Date(newMessage.editedTimestamp))),
                         mentions: renderNumberDelta(oldMessage.mentions.users.size, newMessage.mentions.users.size),
-                        attachments: renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size)
+                        attachments: entry(
+                            renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size),
+                            renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size) + attachmentJump
+                        )
                     },
                     hidden: {
                         guild: newMessage.channel.guild.id
                     }
                 }
-                log(data);
+                return log(data);
             }
-            return
         };
+        if (!newMessage.editedTimestamp) { return }
         if (newContent.length > 256) newContent = newContent.substring(0, 253) + '...'
         if (oldContent.length > 256) oldContent = oldContent.substring(0, 253) + '...'
         let data = {
@@ -61,7 +67,10 @@
                 sent: entry(new Date(newMessage.createdTimestamp), renderDelta(new Date(newMessage.createdTimestamp))),
                 edited: entry(new Date(newMessage.editedTimestamp), renderDelta(new Date(newMessage.editedTimestamp))),
                 mentions: renderNumberDelta(oldMessage.mentions.users.size, newMessage.mentions.users.size),
-                attachments: renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size),
+                attachments: entry(
+                    renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size),
+                    renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size) + attachmentJump
+                ),
                 repliedTo: entry(
                     newMessage.reference.messageId || null,
                     newMessage.reference.messageId ? `[[Jump to message]](https://discord.com/channels/${newMessage.guild.id}/${newMessage.channel.id}/${newMessage.reference.messageId})` : "None"
diff --git a/src/events/roleUpdate.ts b/src/events/roleUpdate.ts
index baf4399..7c6ca75 100644
--- a/src/events/roleUpdate.ts
+++ b/src/events/roleUpdate.ts
@@ -13,7 +13,7 @@
         let changes = {
             roleId: entry(nr.id, `\`${nr.id}\``),
             role: entry(nr.id, renderRole(nr)),
-            edited: entry(nr.createdTimestamp, renderDelta(nr.createdTimestamp)),
+            edited: entry(new Date().getTime(), renderDelta(new Date().getTime())),
             editedBy: entry(audit.executor.id, renderUser((await nr.guild.members.fetch(audit.executor.id)).user)),
         }
         let mentionable = ["", ""]
@@ -28,6 +28,8 @@
         if (or.mentionable != nr.mentionable) changes["mentionable"] = entry([or.mentionable, nr.mentionable], `${mentionable[0]} -> ${mentionable[1]}`);
         if (or.hexColor != nr.hexColor) changes["color"] = entry([or.hexColor, nr.hexColor], `\`${or.hexColor}\` -> \`${nr.hexColor}\``);
 
+        if (Object.keys(changes).length == 4) return
+
         let data = {
             meta:{
                 type: 'roleUpdate',
@@ -41,7 +43,7 @@
             hidden: {
                 guild: nr.guild.id
             }
-        } // TODO: show perms changed
+        } // TODO: show perms changed (webpage)
         log(data);
     } catch {}
 }
\ No newline at end of file
diff --git a/src/events/webhookUpdate.ts b/src/events/webhookUpdate.ts
index a20608c..66b1cd0 100644
--- a/src/events/webhookUpdate.ts
+++ b/src/events/webhookUpdate.ts
@@ -72,7 +72,7 @@
             hidden: {
                 guild: channel.guild.id
             }
-        } // TODO
+        }
         log(data);
     } catch(e) { console.log(e) }
 }