feat: uwuify proxy
vi v@vt3e.cat
Sat, 21 Mar 2026 03:52:45 +0000
5 files changed,
175 insertions(+),
4 deletions(-)
M
src/database/schema/index.ts
→
src/database/schema/index.ts
@@ -2,3 +2,4 @@ export * from "./tickets";
export * from "./guild"; export * from "./attachments"; export * from "./bugs"; +export * from "./userPreferences";
A
src/database/schema/userPreferences.ts
@@ -0,0 +1,10 @@
+import { sqliteTable, text } from "drizzle-orm/sqlite-core"; + +export const userPreferences = sqliteTable("user_preferences", { + userId: text("user_id").primaryKey(), + uwuifyMessages: text("uwuify_messages", { enum: ["enabled", "disabled"] }) + .default("disabled") + .notNull(), +}); + +export type UserPreference = typeof userPreferences.$inferSelect;
M
src/events/messageCreate.ts
→
src/events/messageCreate.ts
@@ -1,9 +1,13 @@
-import { attachments, db, ticketMessages, tickets } from "@/database"; +import { + attachments, + db, + ticketMessages, + tickets, + userPreferences, +} from "@/database"; import { getPublicUrl, s3 } from "@/utils/s3"; import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, + AttachmentBuilder, type Client, Events, type GuildMember,@@ -11,6 +15,7 @@ type Message,
} from "discord.js"; import { and, eq } from "drizzle-orm"; import { nanoid } from "nanoid"; +import Uwuifier from "uwuifier"; import config from "@/config"; import { loggers } from "@/utils/logging";@@ -19,6 +24,110 @@ const logger = loggers.events.child({ name: "messageCreate" });
type UploadStatus = "queued" | "uploading" | "done" | "failed"; +async function handleUwuification(message: Message): Promise<boolean> { + if (message.author.bot) return false; + if (!message.content && message.attachments.size === 0) return false; + + const userPref = db + .select() + .from(userPreferences) + .where(eq(userPreferences.userId, message.author.id)) + .get(); + + if (userPref?.uwuifyMessages !== "enabled") return false; + + const uwuifier = new Uwuifier(); + const uwuifiedContent = message.content + ? uwuifier.uwuifySentence(message.content) + : ""; + + const blacklistedWords = [ + "twerks", + "sees bulge", + "notices buldge", + "starts twerking", + ]; + + const finalText = blacklistedWords.reduce((acc, word) => { + return acc.replace(new RegExp(word, "gi"), "----"); + }, uwuifiedContent); + + try { + let replyReference = null; + if (message.reference?.messageId) { + try { + replyReference = await message.channel.messages.fetch( + message.reference.messageId, + ); + } catch (error) { + logger.warn( + error, + "Failed to fetch referenced message for uwuified reply", + ); + } + } + + const files: AttachmentBuilder[] = []; + for (const attachment of message.attachments.values()) { + try { + const resp = await fetch(attachment.url); + if (!resp.ok) { + logger.warn( + `Failed to fetch attachment ${attachment.name}, status ${resp.status}`, + ); + continue; + } + + const buffer = await resp.arrayBuffer(); + const attachmentBuilder = new AttachmentBuilder(Buffer.from(buffer), { + name: attachment.name, + }); + files.push(attachmentBuilder); + } catch (error) { + logger.error(error, `Failed to download attachment ${attachment.name}`); + } + } + + await message.delete(); + + const contentParts = [ + `**<@${message.author.id}>**: ${finalText || "(no text)"}`, + ]; + + if (message.channel.isSendable()) { + const sendOptions: { + content: string; + files?: AttachmentBuilder[]; + reply?: { messageReference: string }; + } = { + content: contentParts.join("\n"), + }; + + if (files.length > 0) { + sendOptions.files = files; + } + + if (replyReference) { + sendOptions.reply = { + messageReference: replyReference.id, + }; + } + + await message.channel.send({ + allowedMentions: { + users: [], + }, + ...sendOptions, + }); + } + + return true; + } catch (error) { + logger.error(error, "Failed to uwuify and resend message"); + return false; + } +} + export default { event: Events.MessageCreate, async execute(client: Client, message: Message) {@@ -46,6 +155,8 @@ message.content.includes("gorque is this true")
) { message.channel.send("oui 🇫🇷🥖"); } + + await handleUwuification(message); const ticket = db .select()
A
src/interactions/commands/uwuifyProxy.ts
@@ -0,0 +1,49 @@
+import { db, userPreferences } from "@/database"; +import { + type ChatInputCommandInteraction, + type Client, + SlashCommandBuilder, +} from "discord.js"; +import { eq } from "drizzle-orm"; + +const commandData = new SlashCommandBuilder() + .setName("uwuify-toggle") + .setDescription("toggle automatic uwuification of your messages"); + +async function execute( + _client: Client, + interaction: ChatInputCommandInteraction, +) { + const userId = interaction.user.id; + + const existing = db + .select() + .from(userPreferences) + .where(eq(userPreferences.userId, userId)) + .get(); + + const isCurrentlyEnabled = existing?.uwuifyMessages === "enabled"; + const newState = isCurrentlyEnabled ? "disabled" : "enabled"; + + if (existing) { + await db + .update(userPreferences) + .set({ uwuifyMessages: newState }) + .where(eq(userPreferences.userId, userId)); + } else { + await db.insert(userPreferences).values({ + userId, + uwuifyMessages: newState, + }); + } + + const status = newState === "enabled" ? "enabled" : "disabled"; + await interaction.reply({ + content: `✅ uwuification ${status}!`, + }); +} + +export default { + data: commandData, + execute, +};