made premium check faster. Added transcript endpoint, toHumanReadable function.
diff --git a/src/actions/tickets/delete.ts b/src/actions/tickets/delete.ts
index a1b4b1a..be891ec 100644
--- a/src/actions/tickets/delete.ts
+++ b/src/actions/tickets/delete.ts
@@ -4,6 +4,7 @@
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
 import { preloadPage } from '../../utils/createTemporaryStorage.js';
+import { LoadingEmbed } from '../../utils/defaults.js';
 
 export default async function (interaction: Discord.CommandInteraction | ButtonInteraction) {
     if (!interaction.guild) return;
@@ -68,8 +69,9 @@
 
         await channel.delete();
     } else if (status === "Active") {
-        // Close the ticket
-
+        await interaction.reply({embeds: LoadingEmbed, fetchReply: true});
+        // Archive the ticket
+        await interaction.channel.fetch()
         if (channel.isThread()) {
             channel.setName(`${channel.name.replace("Active", "Archived")}`);
             channel.members.remove(channel.name.split(" - ")[1]!);
@@ -79,13 +81,14 @@
             await channel.permissionOverwrites.delete(channel.topic!.split(" ")[0]!);
         }
         preloadPage(interaction.channel.id, "privacy", "2")
-        await interaction.reply({
+        const hasPremium = await client.database.premium.hasPremium(interaction.guild.id);
+        await interaction.editReply({
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Archived Ticket")
                     .setDescription(`This ticket has been Archived. Type ${getCommandMentionByName("ticket/close")} to delete it.\n` +
                         "Creating a transcript will delete all messages in this ticket" +
-                        await client.database.premium.hasPremium(interaction.guild.id) ?
+                        hasPremium ?
                         `\n\nFor more info on transcripts, check ${getCommandMentionByName("privacy")}` :
                         "")
                     .setStatus("Warning")
@@ -100,7 +103,7 @@
                             .setCustomId("closeticket")
                             .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
                     ].concat(
-                        await client.database.premium.hasPremium(interaction.guild.id)
+                        hasPremium
                             ? [
                                     new ButtonBuilder()
                                         .setLabel("Create Transcript and Delete")
@@ -198,4 +201,4 @@
     log(data);
 }
 
-export { purgeByUser };
\ No newline at end of file
+export { purgeByUser };
diff --git a/src/api/index.ts b/src/api/index.ts
index bfe9d18..6a90c48 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -149,6 +149,16 @@
         return res.sendStatus(404);
     });
 
+    app.get("/transcript/:code", jsonParser, async function (req: express.Request, res: express.Response) {
+        const code = req.params.code;
+        if (code === undefined) return res.status(400).send("No code provided");
+        const entry = await client.database.transcripts.read(code);
+        if (entry === null) return res.status(404).send("Could not find a transcript by that code");
+        // Convert to a human readable format
+        const data = client.database.transcripts.toHumanReadable(entry);
+        return res.status(200).send(data);
+    });
+
     app.listen(port);
 };
 
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index 8d49c3b..5e0a795 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -1,4 +1,3 @@
-import { JSONTranscriptFromMessageArray, JSONTranscriptToHumanReadable } from '../../utils/logTranscripts.js';
 import Discord, { CommandInteraction, GuildChannel, GuildMember, TextChannel, ButtonStyle, ButtonBuilder } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "discord.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
@@ -161,7 +160,8 @@
             }
         };
         log(data);
-        const transcript = JSONTranscriptToHumanReadable(JSONTranscriptFromMessageArray(deleted)!);
+        const newOut = await client.database.transcripts.createTranscript(deleted, interaction, interaction.member as GuildMember);
+        const transcript = client.database.transcripts.toHumanReadable(newOut);
         const attachmentObject = {
             attachment: Buffer.from(transcript),
             name: `purge-${channel.id}-${Date.now()}.txt`,
diff --git a/src/commands/nucleus/premium.ts b/src/commands/nucleus/premium.ts
index b31accb..325c360 100644
--- a/src/commands/nucleus/premium.ts
+++ b/src/commands/nucleus/premium.ts
@@ -67,7 +67,7 @@
 }
 
 const callback = async (interaction: CommandInteraction): Promise<void> => {
-
+    if (interaction.guild) client.database.premium.hasPremium(interaction.guild.id).finally(() => {});
     await interaction.reply({embeds: LoadingEmbed, ephemeral: true})
     const member = await (await interaction.client.guilds.fetch("684492926528651336")).members.fetch(interaction.user.id).catch(() => {
         interaction.editReply({ embeds: [
@@ -172,7 +172,7 @@
             components: []
         });
     } else {
-        client.database.premium.addPremium(interaction.user.id, guild.id);
+        await client.database.premium.addPremium(interaction.user.id, guild.id);
         interaction.editReply({
             embeds: [
                 new EmojiEmbed()
diff --git a/src/commands/server/buttons.ts b/src/commands/server/buttons.ts
index e4bda0d..3297616 100644
--- a/src/commands/server/buttons.ts
+++ b/src/commands/server/buttons.ts
@@ -32,7 +32,7 @@
 const buttonNames: Record<string, string> = {
     verifybutton: "Verify",
     rolemenu: "Role Menu",
-    createticket: "Ticket"
+    createticket: "Create Ticket"
 }
 
 export const callback = async (interaction: CommandInteraction): Promise<void> => {
@@ -195,8 +195,8 @@
                         continue;
                     }
                     if (!out || out.isButton()) continue
-                    data.title = out.fields.getTextInputValue("title");
-                    data.description = out.fields.getTextInputValue("description");
+                    data.title = out.fields.getTextInputValue("title").length === 0 ? null : out.fields.getTextInputValue("title");
+                    data.description = out.fields.getTextInputValue("description").length === 0 ? null : out.fields.getTextInputValue("description");
                     break;
                 }
                 case "send": {
diff --git a/src/commands/settings/logs/attachment.ts b/src/commands/settings/logs/attachment.ts
index c04c7cf..238b8b9 100644
--- a/src/commands/settings/logs/attachment.ts
+++ b/src/commands/settings/logs/attachment.ts
@@ -12,6 +12,7 @@
         .setDescription("Where attachments should be logged to (Premium only)")
 
 const callback = async (interaction: CommandInteraction): Promise<unknown> => {
+    if (interaction.guild) client.database.premium.hasPremium(interaction.guild.id).finally(() => {});
     await interaction.reply({
         embeds: LoadingEmbed,
         ephemeral: true,
diff --git a/src/premium/attachmentLogs.ts b/src/premium/attachmentLogs.ts
index 3c583f2..b2c8391 100644
--- a/src/premium/attachmentLogs.ts
+++ b/src/premium/attachmentLogs.ts
@@ -8,6 +8,7 @@
 import type { GuildTextBasedChannel, Message } from "discord.js";
 
 export default async function logAttachment(message: Message): Promise<AttachmentLogSchema> {
+    if (message.guild) client.database.premium.hasPremium(message.guild.id).finally(() => {});
     if (!message.guild) throw new Error("Tried to log an attachment in a non-guild message");
     const { renderUser, renderChannel, renderDelta } = client.logger;
     const attachments = [];
diff --git a/src/premium/createTranscript.ts b/src/premium/createTranscript.ts
index 20b790a..85e059f 100644
--- a/src/premium/createTranscript.ts
+++ b/src/premium/createTranscript.ts
@@ -8,83 +8,13 @@
     TextChannel,
     ButtonStyle,
     User,
-    ComponentType,
     ThreadChannel
 } from "discord.js";
 import EmojiEmbed from "../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../utils/getEmojiByName.js";
-import { PasteClient, Publicity, ExpireDate } from "pastebin-api";
 import client from "../utils/client.js";
 import { messageException } from '../utils/createTemporaryStorage.js';
 
-const pbClient = new PasteClient(client.config.pastebinApiKey);
-
-interface TranscriptEmbed {
-    title?: string;
-    description?: string;
-    fields?: {
-        name: string;
-        value: string;
-        inline: boolean;
-    }[];
-    footer?: {
-        text: string;
-        iconURL?: string;
-    };
-}
-
-interface TranscriptComponent {
-    type: number;
-    style?: ButtonStyle;
-    label?: string;
-    description?: string;
-    placeholder?: string;
-    emojiURL?: string;
-}
-
-interface TranscriptAuthor {
-    username: string;
-    discriminator: number;
-    nickname?: string;
-    id: string;
-    iconURL?: string;
-    topRole: {
-        color: number;
-        badgeURL?: string;
-    }
-}
-
-interface TranscriptAttachment {
-    url: string;
-    filename: string;
-    size: number;
-    log?: string;
-}
-
-interface TranscriptMessage {
-    id: string;
-    author: TranscriptAuthor;
-    content?: string;
-    embeds?: TranscriptEmbed[];
-    components?: TranscriptComponent[][];
-    editedTimestamp?: number;
-    createdTimestamp: number;
-    flags?: string[];
-    attachments?: TranscriptAttachment[];
-    stickerURLs?: string[];
-    referencedMessage?: string | [string, string, string];
-}
-
-interface Transcript {
-    type: "ticket" | "purge"
-    guild: string;
-    channel: string;
-    for: TranscriptAuthor
-    messages: TranscriptMessage[];
-    createdTimestamp: number;
-    createdBy: TranscriptAuthor;
-}
-
 const noTopic = new EmojiEmbed()
     .setTitle("User not found")
     .setDescription("There is no user associated with this ticket.")
@@ -114,175 +44,58 @@
         )
     ));
 
-    let out = "";
-    messages.reverse().forEach((message) => {
-        if (!message.author.bot) {
-            const sentDate = new Date(message.createdTimestamp);
-            out += `${message.author.username}#${message.author.discriminator} (${
-                message.author.id
-            }) [${sentDate.toUTCString()}]\n`;
-            const lines = message.content.split("\n");
-            lines.forEach((line) => {
-                out += `> ${line}\n`;
-            });
-            out += "\n\n";
-        }
-    });
-
-    const interactionMember = await interaction.guild?.members.fetch(interaction.user.id)
-
     let topic
-    let member: GuildMember | null = null;
+    let member: GuildMember = interaction.guild?.members.me!;
     if (interaction.channel instanceof TextChannel) {
         topic = interaction.channel.topic;
         if (topic === null) return await interaction.reply({ embeds: [noTopic] });
-        member = interaction.guild!.members.cache.get(topic.split(" ")[1]!) ?? null;
+        const mem = interaction.guild!.members.cache.get(topic.split(" ")[1]!);
+        if (mem) member = mem;
     } else {
         topic = interaction.channel.name;
         const split = topic.split("-").map(p => p.trim()) as [string, string, string];
-        member = interaction.guild!.members.cache.get(split[1]) ?? null;
-        if (member === null) return await interaction.reply({ embeds: [noTopic] });
+        const mem = interaction.guild!.members.cache.get(split[1])
+        if (mem) member = mem;
     }
 
-
-    const newOut: Transcript = {
-        type: "ticket",
-        for: {
-            username: member!.user.username,
-            discriminator: parseInt(member!.user.discriminator),
-            id: member!.user.id,
-            topRole: {
-                color: member!.roles.highest.color
-            }
-        },
-        guild: interaction.guild!.id,
-        channel: interaction.channel!.id,
-        messages: [],
-        createdTimestamp: Date.now(),
-        createdBy: {
-            username: interaction.user.username,
-            discriminator: parseInt(interaction.user.discriminator),
-            id: interaction.user.id,
-            topRole: {
-                color: interactionMember?.roles.highest.color ?? 0x000000
-            }
-        }
-    }
-    if(interactionMember?.roles.icon) newOut.createdBy.topRole.badgeURL = interactionMember.roles.icon.iconURL()!;
-    messages.reverse().forEach((message) => {
-        const msg: TranscriptMessage = {
-            id: message.id,
-            author: {
-                username: message.author.username,
-                discriminator: parseInt(message.author.discriminator),
-                id: message.author.id,
-                topRole: {
-                    color: message.member!.roles.highest.color
-                }
-            },
-            createdTimestamp: message.createdTimestamp
-        };
-        if (message.member!.roles.icon) msg.author.topRole.badgeURL = message.member!.roles.icon.iconURL()!;
-        if (message.content) msg.content = message.content;
-        if (message.embeds.length > 0) msg.embeds = message.embeds.map(embed => {
-            const obj: TranscriptEmbed = {};
-            if (embed.title) obj.title = embed.title;
-            if (embed.description) obj.description = embed.description;
-            if (embed.fields.length > 0) obj.fields = embed.fields.map(field => {
-                return {
-                    name: field.name,
-                    value: field.value,
-                    inline: field.inline ?? false
-                }
-            });
-            if (embed.footer) obj.footer = {
-                text: embed.footer.text,
-            };
-            if (embed.footer?.iconURL) obj.footer!.iconURL = embed.footer.iconURL;
-            return obj;
-        });
-        if (message.components.length > 0) msg.components = message.components.map(component => component.components.map(child => {
-            const obj: TranscriptComponent = {
-                type: child.type
-            }
-            if (child.type === ComponentType.Button) {
-                obj.style = child.style;
-                obj.label = child.label ?? "";
-            } else if (child.type > 2) {
-                obj.placeholder = child.placeholder ?? "";
-            }
-            return obj
-        }));
-        if (message.editedTimestamp) msg.editedTimestamp = message.editedTimestamp;
-        msg.flags = message.flags.toArray();
-
-        if (message.stickers.size > 0) msg.stickerURLs = message.stickers.map(sticker => sticker.url);
-        if (message.reference) msg.referencedMessage = [message.reference.guildId ?? "", message.reference.channelId, message.reference.messageId ?? ""];
-        newOut.messages.push(msg);
-    });
+    const newOut = await client.database.transcripts.createTranscript(messages, interaction, member);
 
     const code = await client.database.transcripts.create(newOut);
-    if(!code) return await interaction.reply({embeds: [new EmojiEmbed().setTitle("Error").setDescription("An error occurred while creating the transcript.").setStatus("Danger").setEmoji("CONTROL.BLOCKCROSS")]})
-    let m: Message;
-    if (out !== "") {
-        const url = await pbClient.createPaste({
-            code: out,
-            expireDate: ExpireDate.Never,
-            name:
-                `Ticket Transcript ${
-                    member ? "for " + member.user.username + "#" + member.user.discriminator + " " : ""
-                }` + `(Created at ${new Date(interaction.channel.createdTimestamp!).toDateString()})`,
-            publicity: Publicity.Unlisted
-        });
-        const guildConfig = await client.database.guilds.read(interaction.guild!.id);
-        m = (await interaction.reply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Transcript")
-                    .setDescription(
-                        "You can view the transcript using the link below. You can save the link for later" +
-                            (guildConfig.logging.logs.channel
-                                ? ` or find it in <#${guildConfig.logging.logs.channel}> once you press delete below. After this the channel will be deleted.`
-                                : ".")
-                    )
-                    .setStatus("Success")
-                    .setEmoji("CONTROL.DOWNLOAD")
-            ],
-            components: [
-                new ActionRowBuilder<ButtonBuilder>().addComponents([
-                    new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(url),
-                    new ButtonBuilder()
-                        .setLabel("Delete")
-                        .setStyle(ButtonStyle.Danger)
-                        .setCustomId("close")
-                        .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
-                ])
-            ],
-            fetchReply: true
-        })) as Message;
-    } else {
-        m = (await interaction.reply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Transcript")
-                    .setDescription(
-                        "The transcript was empty, so no changes were made. To delete this ticket, press the delete button below."
-                    )
-                    .setStatus("Success")
-                    .setEmoji("CONTROL.DOWNLOAD")
-            ],
-            components: [
-                new ActionRowBuilder<ButtonBuilder>().addComponents([
-                    new ButtonBuilder()
-                        .setLabel("Delete")
-                        .setStyle(ButtonStyle.Danger)
-                        .setCustomId("close")
-                        .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
-                ])
-            ],
-            fetchReply: true
-        })) as Message;
-    }
+    if(!code) return await interaction.reply({
+        embeds: [
+            new EmojiEmbed()
+                .setTitle("Error")
+                .setDescription("An error occurred while creating the transcript.")
+                .setStatus("Danger")
+                .setEmoji("CONTROL.BLOCKCROSS")
+        ]
+    })
+    const guildConfig = await client.database.guilds.read(interaction.guild!.id);
+    const m: Message = (await interaction.reply({
+        embeds: [
+            new EmojiEmbed()
+                .setTitle("Transcript")
+                .setDescription(
+                    "You can view the transcript using the link below. You can save the link for later" +
+                        (guildConfig.logging.logs.channel
+                            ? ` or find it in <#${guildConfig.logging.logs.channel}> once you press delete below. After this the channel will be deleted.`
+                            : ".")
+                )
+                .setStatus("Success")
+                .setEmoji("CONTROL.DOWNLOAD")
+        ],
+        components: [
+            new ActionRowBuilder<ButtonBuilder>().addComponents([
+                new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript?code=${code}`),
+                new ButtonBuilder()
+                    .setLabel("Delete")
+                    .setStyle(ButtonStyle.Danger)
+                    .setCustomId("close")
+                    .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+            ])
+        ],
+        fetchReply: true
+    })) as Message;
     let i;
     try {
         i = await m.awaitMessageComponent({
@@ -303,7 +116,7 @@
             timestamp: Date.now()
         },
         list: {
-            ticketFor: member ? entry(member.id, renderUser(member.user)) : entry(null, "*Unknown*"),
+            ticketFor: entry(member.id, renderUser(member.user)),
             deletedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as User)),
             deleted: entry(Date.now().toString(), renderDelta(Date.now()))
         },
diff --git a/src/utils/client.ts b/src/utils/client.ts
index 00f8c05..7e84716 100644
--- a/src/utils/client.ts
+++ b/src/utils/client.ts
@@ -2,7 +2,7 @@
 import { Logger } from "../utils/log.js";
 import Memory from "../utils/memory.js";
 import type { VerifySchema } from "../reflex/verify.js";
-import { Guilds, History, ModNotes, Premium, PerformanceTest, ScanCache, Transcript } from "../utils/database.js";
+import { Guilds, History, ModNotes, Premium, PerformanceTest, ScanCache, Transcript,  } from "../utils/database.js";
 import EventScheduler from "../utils/eventScheduler.js";
 import type { RoleMenuSchema } from "../actions/roleMenu.js";
 import config from "../config/main.js";
diff --git a/src/utils/commandRegistration/register.ts b/src/utils/commandRegistration/register.ts
index 78e3b0f..d88a13a 100644
--- a/src/utils/commandRegistration/register.ts
+++ b/src/utils/commandRegistration/register.ts
@@ -225,6 +225,6 @@
     console.log(`${colors.green}Registered commands, events and context menus${colors.none}`)
     console.log(
         (config.enableDevelopment ? `${colors.purple}Bot started in Development mode` :
-        `${colors.blue}Bot started in Production mode`) + colors.none)
-    // console.log(client.commands)
+        `${colors.blue}Bot started in Production mode`) + colors.none
+    )
 };
diff --git a/src/utils/database.ts b/src/utils/database.ts
index 7e80f96..b7971c3 100644
--- a/src/utils/database.ts
+++ b/src/utils/database.ts
@@ -1,4 +1,4 @@
-import type { ButtonStyle, GuildMember } from "discord.js";
+import { ButtonStyle, CommandInteraction, ComponentType, GuildMember, Message, MessageComponentInteraction } from "discord.js";
 import type Discord from "discord.js";
 import { Collection, MongoClient } from "mongodb";
 import config from "../config/main.js";
@@ -154,7 +154,7 @@
     flags?: string[];
     attachments?: TranscriptAttachment[];
     stickerURLs?: string[];
-    referencedMessage?: string | [string, string, string];
+    referencedMessage?: string | [string, string, string];  // the message id, the channel id, the guild id
 }
 
 interface TranscriptSchema {
@@ -189,6 +189,134 @@
     async read(code: string) {
         return await this.transcripts.findOne({ code: code });
     }
+
+    async createTranscript(messages: Message[], interaction: MessageComponentInteraction | CommandInteraction, member: GuildMember) {
+        const interactionMember = await interaction.guild?.members.fetch(interaction.user.id)
+        const newOut: Omit<TranscriptSchema, "code"> = {
+            type: "ticket",
+            for: {
+                username: member!.user.username,
+                discriminator: parseInt(member!.user.discriminator),
+                id: member!.user.id,
+                topRole: {
+                    color: member!.roles.highest.color
+                }
+            },
+            guild: interaction.guild!.id,
+            channel: interaction.channel!.id,
+            messages: [],
+            createdTimestamp: Date.now(),
+            createdBy: {
+                username: interaction.user.username,
+                discriminator: parseInt(interaction.user.discriminator),
+                id: interaction.user.id,
+                topRole: {
+                    color: interactionMember?.roles.highest.color ?? 0x000000
+                }
+            }
+        }
+        if(interactionMember?.roles.icon) newOut.createdBy.topRole.badgeURL = interactionMember.roles.icon.iconURL()!;
+        messages.reverse().forEach((message) => {
+            const msg: TranscriptMessage = {
+                id: message.id,
+                author: {
+                    username: message.author.username,
+                    discriminator: parseInt(message.author.discriminator),
+                    id: message.author.id,
+                    topRole: {
+                        color: message.member!.roles.highest.color
+                    }
+                },
+                createdTimestamp: message.createdTimestamp
+            };
+            if (message.member!.roles.icon) msg.author.topRole.badgeURL = message.member!.roles.icon.iconURL()!;
+            if (message.content) msg.content = message.content;
+            if (message.embeds.length > 0) msg.embeds = message.embeds.map(embed => {
+                const obj: TranscriptEmbed = {};
+                if (embed.title) obj.title = embed.title;
+                if (embed.description) obj.description = embed.description;
+                if (embed.fields.length > 0) obj.fields = embed.fields.map(field => {
+                    return {
+                        name: field.name,
+                        value: field.value,
+                        inline: field.inline ?? false
+                    }
+                });
+                if (embed.footer) obj.footer = {
+                    text: embed.footer.text,
+                };
+                if (embed.footer?.iconURL) obj.footer!.iconURL = embed.footer.iconURL;
+                return obj;
+            });
+            if (message.components.length > 0) msg.components = message.components.map(component => component.components.map(child => {
+                const obj: TranscriptComponent = {
+                    type: child.type
+                }
+                if (child.type === ComponentType.Button) {
+                    obj.style = child.style;
+                    obj.label = child.label ?? "";
+                } else if (child.type > 2) {
+                    obj.placeholder = child.placeholder ?? "";
+                }
+                return obj
+            }));
+            if (message.editedTimestamp) msg.editedTimestamp = message.editedTimestamp;
+            msg.flags = message.flags.toArray();
+
+            if (message.stickers.size > 0) msg.stickerURLs = message.stickers.map(sticker => sticker.url);
+            if (message.reference) msg.referencedMessage = [message.reference.guildId ?? "", message.reference.channelId, message.reference.messageId ?? ""];
+            newOut.messages.push(msg);
+        });
+        return newOut;
+    }
+
+    toHumanReadable(transcript: Omit<TranscriptSchema, "code">): string {
+        let out = "";
+        for (const message of transcript.messages) {
+            if (message.referencedMessage) {
+                if (Array.isArray(message.referencedMessage)) {
+                    out += `> [Crosspost From] ${message.referencedMessage[0]} in ${message.referencedMessage[1]} in ${message.referencedMessage[2]}\n`;
+                }
+                else out += `> [Reply To] ${message.referencedMessage}\n`;
+            }
+            out += `${message.author.nickname ?? message.author.username}#${message.author.discriminator} (${message.author.id}) (${message.id}) `;
+            out += `[${new Date(message.createdTimestamp).toISOString()}] `;
+            if (message.editedTimestamp) out += `[Edited: ${new Date(message.editedTimestamp).toISOString()}] `;
+            out += "\n";
+            if (message.content) out += `[Content]\n${message.content}\n\n`;
+            if (message.embeds) {
+                for (const embed of message.embeds) {
+                    out += `[Embed]\n`;
+                    if (embed.title) out += `| Title: ${embed.title}\n`;
+                    if (embed.description) out += `| Description: ${embed.description}\n`;
+                    if (embed.fields) {
+                        for (const field of embed.fields) {
+                            out += `| Field: ${field.name} - ${field.value}\n`;
+                        }
+                    }
+                    if (embed.footer) {
+                        out += `|Footer: ${embed.footer.text}\n`;
+                    }
+                    out += "\n";
+                }
+            }
+            if (message.components) {
+                for (const component of message.components) {
+                    out += `[Component]\n`;
+                    for (const button of component) {
+                        out += `| Button: ${button.label ?? button.description}\n`;
+                    }
+                    out += "\n";
+                }
+            }
+            if (message.attachments) {
+                for (const attachment of message.attachments) {
+                    out += `[Attachment] ${attachment.filename} (${attachment.size} bytes) ${attachment.url}\n`;
+                }
+            }
+        }
+        return out
+    }
 }
 
 export class History {
@@ -317,9 +445,12 @@
 
 export class Premium {
     premium: Collection<PremiumSchema>;
+    cache: Map<string, [boolean, string, number, boolean, Date]>;  // Date indicates the time one hour after it was created
+    cacheTimeout = 1000 * 60 * 60;  // 1 hour
 
     constructor() {
         this.premium = database.collection<PremiumSchema>("premium");
+        this.cache = new Map<string, [boolean, string, number, boolean, Date]>();
     }
 
     async updateUser(user: string, level: number) {
@@ -337,8 +468,11 @@
     }
 
     async hasPremium(guild: string): Promise<[boolean, string, number, boolean] | null> {
+        // [Has premium, user giving premium, level, is mod: if given automatically]
+        const cached = this.cache.get(guild);
+        if (cached && cached[4].getTime() < Date.now()) return [cached[0], cached[1], cached[2], cached[3]];
         const entries = await this.premium.find({}).toArray();
-        const members = await (await client.guilds.fetch(guild)).members.fetch()
+        const members = (await client.guilds.fetch(guild)).members.cache
         for(const {user} of entries) {
             const member = members.get(user);
             if(member) { //TODO: Notify user if they've given premium to a server that has since gotten premium via a mod.
@@ -355,7 +489,10 @@
                             member.permissions.has("ManageMessages") ||
                             member.permissions.has("ManageThreads")
                 const entry = entries.find(e => e.user === member.id);
-                if(entry && (entry.level === 3) && modPerms) return [true, member.id, entry.level, true];
+                if(entry && (entry.level === 3) && modPerms) {
+                    this.cache.set(guild, [true, member.id, entry.level, true, new Date(Date.now() + this.cacheTimeout)]);
+                    return [true, member.id, entry.level, true];
+                }
             }
         }
         const entry = await this.premium.findOne({
@@ -365,6 +502,7 @@
                 }
             }
         });
+        this.cache.set(guild, [entry ? true : false, entry?.user ?? "", entry?.level ?? 0, false, new Date(Date.now() + this.cacheTimeout)]);
         return entry ? [true, entry.user, entry.level, false] : null;
     }
 
@@ -427,11 +565,14 @@
         }
     }
 
-    addPremium(user: string, guild: string) {
+    async addPremium(user: string, guild: string) {
+        const { level } = (await this.fetchUser(user))!;
+        this.cache.set(guild, [true, user, level, false, new Date(Date.now() + this.cacheTimeout)]);
         return this.premium.updateOne({ user: user }, { $addToSet: { appliesTo: guild } }, { upsert: true });
     }
 
     removePremium(user: string, guild: string) {
+        this.cache.set(guild, [false, "", 0, false, new Date(Date.now() + this.cacheTimeout)]);
         return this.premium.updateOne({ user: user }, { $pull: { appliesTo: guild } });
     }
 }
diff --git a/src/utils/eventScheduler.ts b/src/utils/eventScheduler.ts
index bdd0d21..5c461ad 100644
--- a/src/utils/eventScheduler.ts
+++ b/src/utils/eventScheduler.ts
@@ -14,7 +14,6 @@
                 collection: "eventScheduler"
             }
         });
-
         this.agenda.define("unmuteRole", async (job) => {
             const guild = await client.guilds.fetch(job.attrs.data.guild);
             const user = await guild.members.fetch(job.attrs.data.user);
diff --git a/src/utils/logTranscripts.ts b/src/utils/logTranscripts.ts
deleted file mode 100644
index 0950664..0000000
--- a/src/utils/logTranscripts.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import type Discord from 'discord.js';
-
-export interface JSONTranscriptSchema {
-    messages: {
-        content: string | null;
-        attachments: {
-            url: string;
-            name: string;
-            size: number;
-        }[];
-        authorID: string;
-        authorUsername: string;
-        authorUsernameColor: string;
-        timestamp: string;
-        id: string;
-        edited: boolean;
-    }[];
-    channel: string;
-    guild: string;
-    timestamp: string;
-}
-
-
-export const JSONTranscriptFromMessageArray = (messages: Discord.Message[]): JSONTranscriptSchema | null => {
-    if (messages.length === 0) return null;
-    return {
-        guild: messages[0]!.guild!.id,
-        channel: messages[0]!.channel.id,
-        timestamp: Date.now().toString(),
-        messages: messages.map((message: Discord.Message) => {
-            return {
-                content: message.content,
-                attachments: message.attachments.map((attachment: Discord.Attachment) => {
-                    return {
-                        url: attachment.url,
-                        name: attachment.name!,
-                        size: attachment.size,
-                    };
-                }),
-                authorID: message.author.id,
-                authorUsername: message.author.username + "#" + message.author.discriminator,
-                authorUsernameColor: message.member!.displayHexColor.toString(),
-                timestamp: message.createdTimestamp.toString(),
-                id: message.id,
-                edited: message.editedTimestamp ? true : false,
-            };
-        })
-    };
-}
-
-export const JSONTranscriptToHumanReadable = (data: JSONTranscriptSchema): string => {
-    let out = "";
-
-    for (const message of data.messages) {
-        const date = new Date(parseInt(message.timestamp));
-        out += `${message.authorUsername} (${message.authorID}) [${date}]`;
-        if (message.edited) out += " (edited)";
-        if (message.content) out += "\nContent:\n" + message.content.split("\n").map((line: string) => `\n> ${line}`).join("");
-        if (message.attachments.length > 0) out += "\nAttachments:\n" + message.attachments.map((attachment: { url: string; name: string; size: number; }) => `\n> [${attachment.name}](${attachment.url}) (${attachment.size} bytes)`).join("\n");
-
-        out += "\n\n";
-    }
-    return out;
-}
\ No newline at end of file