summaryrefslogtreecommitdiff
path: root/packages/gateway/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/gateway/src')
-rw-r--r--packages/gateway/src/commands/crp.ts128
-rw-r--r--packages/gateway/src/commands/react.ts45
-rw-r--r--packages/gateway/src/commands/say.ts176
-rw-r--r--packages/gateway/src/commands/start.ts114
-rw-r--r--packages/gateway/src/commands/utilities.ts1
-rw-r--r--packages/gateway/src/listeners/announcementReaction.ts14
-rw-r--r--packages/gateway/src/listeners/artMediaModeration.ts58
-rw-r--r--packages/gateway/src/listeners/clientReady.ts22
-rw-r--r--packages/gateway/src/listeners/iqdbModeration.ts366
-rw-r--r--packages/gateway/src/listeners/moderationAgent/index.ts367
-rw-r--r--packages/gateway/src/listeners/moderationAgent/utilities.ts1
-rw-r--r--packages/gateway/src/listeners/roleMentionCooldown.ts87
-rw-r--r--packages/gateway/src/listeners/roleplayUmagram.ts68
13 files changed, 706 insertions, 741 deletions
diff --git a/packages/gateway/src/commands/crp.ts b/packages/gateway/src/commands/crp.ts
index 8503cb3..4758574 100644
--- a/packages/gateway/src/commands/crp.ts
+++ b/packages/gateway/src/commands/crp.ts
@@ -1,97 +1,97 @@
import { Message, Role } from "discord.js";
export const handleCrpCommand = async (message: Message) => {
- if (message.author.bot) return;
+ if (message.author.bot) return;
- if (message.content.toLowerCase().startsWith("uma!crp")) {
- const application = await message.client.application?.fetch();
- const ownerId = application?.owner?.id;
+ if (message.content.toLowerCase().startsWith("uma!crp")) {
+ const application = await message.client.application?.fetch();
+ const ownerId = application?.owner?.id;
- if (message.author.id !== ownerId) {
- await message.reply("❌ Only the server owner can use this command.");
+ if (message.author.id !== ownerId) {
+ await message.reply("❌ Only the server owner can use this command.");
- return;
- }
+ return;
+ }
+
+ const parameters = message.content.split(" ").slice(1);
+
+ if (parameters.length < 2) {
+ await message.reply(
+ "❌ Usage: `uma!crp <source_role_mention> <target_role_mention1> [target_role_mention2] ...`\nExample: `uma!crp @everyone @test1 @test2 @test3`",
+ );
+
+ return;
+ }
- const parameters = message.content.split(" ").slice(1);
+ const sourceRoleMention = parameters[0];
+ const targetRoleMentions = parameters.slice(1);
+ let sourceRole: Role | undefined;
- if (parameters.length < 2) {
+ if (sourceRoleMention === "@everyone") {
+ sourceRole = message.guild?.roles.everyone;
+ } else {
+ const sourceRoleMatch = sourceRoleMention.match(/<@&(\d+)>/);
+
+ if (!sourceRoleMatch) {
await message.reply(
- "❌ Usage: `uma!crp <source_role_mention> <target_role_mention1> [target_role_mention2] ...`\nExample: `uma!crp @everyone @test1 @test2 @test3`",
+ "❌ Please mention a valid source role. Example: `@everyone` or `@RoleName`",
);
return;
}
- const sourceRoleMention = parameters[0];
- const targetRoleMentions = parameters.slice(1);
- let sourceRole: Role | undefined;
+ const sourceRoleId = sourceRoleMatch[1];
- if (sourceRoleMention === "@everyone") {
- sourceRole = message.guild?.roles.everyone;
- } else {
- const sourceRoleMatch = sourceRoleMention.match(/<@&(\d+)>/);
+ sourceRole = message.guild?.roles.cache.get(sourceRoleId);
+ }
- if (!sourceRoleMatch) {
- await message.reply(
- "❌ Please mention a valid source role. Example: `@everyone` or `@RoleName`",
- );
+ if (!sourceRole) {
+ await message.reply("❌ Source role not found.");
- return;
- }
+ return;
+ }
- const sourceRoleId = sourceRoleMatch[1];
+ const targetRoles: Role[] = [];
- sourceRole = message.guild?.roles.cache.get(sourceRoleId);
- }
+ for (const mention of targetRoleMentions) {
+ const targetRoleMatch = mention.match(/<@&(\d+)>/);
- if (!sourceRole) {
- await message.reply("❌ Source role not found.");
+ if (!targetRoleMatch) {
+ await message.reply(
+ `❌ Invalid role mention: ${mention}. Please mention valid roles.`,
+ );
return;
}
- const targetRoles: Role[] = [];
+ const targetRoleId = targetRoleMatch[1];
+ const targetRole = message.guild?.roles.cache.get(targetRoleId);
- for (const mention of targetRoleMentions) {
- const targetRoleMatch = mention.match(/<@&(\d+)>/);
+ if (!targetRole) {
+ await message.reply(`❌ Target role not found: ${mention}`);
- if (!targetRoleMatch) {
- await message.reply(
- `❌ Invalid role mention: ${mention}. Please mention valid roles.`,
- );
-
- return;
- }
-
- const targetRoleId = targetRoleMatch[1];
- const targetRole = message.guild?.roles.cache.get(targetRoleId);
-
- if (!targetRole) {
- await message.reply(`❌ Target role not found: ${mention}`);
-
- return;
- }
-
- targetRoles.push(targetRole);
+ return;
}
- try {
- const sourcePermissions = sourceRole.permissions.toArray();
+ targetRoles.push(targetRole);
+ }
- for (const targetRole of targetRoles)
- await targetRole.setPermissions(sourcePermissions);
+ try {
+ const sourcePermissions = sourceRole.permissions.toArray();
- const targetRoleNames = targetRoles.map((role) => role.name).join(", ");
+ for (const targetRole of targetRoles)
+ await targetRole.setPermissions(sourcePermissions);
- await message.reply(
- `✅ Successfully copied permissions from **${sourceRole.name}** to: **${targetRoleNames}**`,
- );
- } catch (error) {
- console.error("Error copying role permissions:", error);
- await message.reply(
- "❌ Failed to copy role permissions. Check bot permissions and try again.",
- );
- }
+ const targetRoleNames = targetRoles.map((role) => role.name).join(", ");
+
+ await message.reply(
+ `✅ Successfully copied permissions from **${sourceRole.name}** to: **${targetRoleNames}**`,
+ );
+ } catch (error) {
+ console.error("Error copying role permissions:", error);
+ await message.reply(
+ "❌ Failed to copy role permissions. Check bot permissions and try again.",
+ );
}
+ }
};
diff --git a/packages/gateway/src/commands/react.ts b/packages/gateway/src/commands/react.ts
index 639dec6..d8a8021 100644
--- a/packages/gateway/src/commands/react.ts
+++ b/packages/gateway/src/commands/react.ts
@@ -1,37 +1,36 @@
import { Message } from "discord.js";
export const handleReactCommand = async (message: Message) => {
- if (message.author.bot) return;
+ if (message.author.bot) return;
- if (!message.content.startsWith("uma!react")) return;
+ if (!message.content.startsWith("uma!react")) return;
- if (!message.guild || message.author.id !== message.guild.ownerId)
- return;
+ if (!message.guild || message.author.id !== message.guild.ownerId) return;
- const parameters = message.content.split(" ");
-
- if (parameters.length < 3) {
- await message.reply("Usage: `uma!react <message_id> <emoji>`");
+ const parameters = message.content.split(" ");
- return;
- }
+ if (parameters.length < 3) {
+ await message.reply("Usage: `uma!react <message_id> <emoji>`");
- const messageId = parameters[1];
- const emoji = parameters[2];
+ return;
+ }
- try {
- const targetMessage = await message.channel.messages.fetch(messageId);
-
- if (!targetMessage) {
- await message.reply("Message not found.");
+ const messageId = parameters[1];
+ const emoji = parameters[2];
- return;
- }
+ try {
+ const targetMessage = await message.channel.messages.fetch(messageId);
- await targetMessage.react(emoji);
- } catch (error) {
- console.error("Error reacting to message:", error);
+ if (!targetMessage) {
+ await message.reply("Message not found.");
- await message.reply("Failed to react to the message.");
+ return;
}
+
+ await targetMessage.react(emoji);
+ } catch (error) {
+ console.error("Error reacting to message:", error);
+
+ await message.reply("Failed to react to the message.");
+ }
};
diff --git a/packages/gateway/src/commands/say.ts b/packages/gateway/src/commands/say.ts
index 31afb04..ec19a33 100644
--- a/packages/gateway/src/commands/say.ts
+++ b/packages/gateway/src/commands/say.ts
@@ -2,124 +2,124 @@ import { Message } from "discord.js";
import { GUILD_ID } from "../constants";
export const handleSayCommand = async (message: Message) => {
- if (message.author.bot) return;
+ if (message.author.bot) return;
- if (message.content.toLowerCase().startsWith("uma!say")) {
- const application = await message.client.application?.fetch();
- const ownerId = application?.owner?.id;
+ if (message.content.toLowerCase().startsWith("uma!say")) {
+ const application = await message.client.application?.fetch();
+ const ownerId = application?.owner?.id;
- if (message.author.id !== ownerId) return;
+ if (message.author.id !== ownerId) return;
- const parameters = message.content.split(" ").slice(1);
+ const parameters = message.content.split(" ").slice(1);
- if (parameters.length < 2) {
- await message.reply(
- "❌ Usage: `uma!say <channel_mention_or_message_id> <message>`\nExamples:\n- `uma!say #general Hello everyone!`\n- `uma!say 1234567890123456789 Thanks for the info!`",
- );
+ if (parameters.length < 2) {
+ await message.reply(
+ "❌ Usage: `uma!say <channel_mention_or_message_id> <message>`\nExamples:\n- `uma!say #general Hello everyone!`\n- `uma!say 1234567890123456789 Thanks for the info!`",
+ );
- return;
- }
+ return;
+ }
- const firstParameter = parameters[0];
- const messageContent = parameters.slice(1).join(" ");
- let targetChannel: any;
- let targetMessage: any = null;
- const messageIdMatch = firstParameter.match(/^\d{17,19}$/);
+ const firstParameter = parameters[0];
+ const messageContent = parameters.slice(1).join(" ");
+ let targetChannel: any;
+ let targetMessage: any = null;
+ const messageIdMatch = firstParameter.match(/^\d{17,19}$/);
- if (messageIdMatch) {
- try {
- const guild = message.client.guilds.cache.get(GUILD_ID);
+ if (messageIdMatch) {
+ try {
+ const guild = message.client.guilds.cache.get(GUILD_ID);
- if (!guild) {
- await message.reply("❌ Guild not found.");
+ if (!guild) {
+ await message.reply("❌ Guild not found.");
- return;
- }
+ return;
+ }
- let foundMessage = null;
+ let foundMessage = null;
- for (const channel of guild.channels.cache.values()) {
- if (channel.isTextBased()) {
- try {
- foundMessage = await channel.messages.fetch(firstParameter);
+ for (const channel of guild.channels.cache.values()) {
+ if (channel.isTextBased()) {
+ try {
+ foundMessage = await channel.messages.fetch(firstParameter);
- if (foundMessage) {
- targetChannel = channel;
- targetMessage = foundMessage;
+ if (foundMessage) {
+ targetChannel = channel;
+ targetMessage = foundMessage;
- break;
- }
- } catch {
- continue;
+ break;
}
+ } catch {
+ continue;
}
}
+ }
- if (!foundMessage) {
- await message.reply("❌ Message not found.");
-
- return;
- }
- } catch {
- await message.reply("❌ Error finding message.");
+ if (!foundMessage) {
+ await message.reply("❌ Message not found.");
return;
}
- } else {
- const channelMatch = firstParameter.match(/<#(\d+)>/);
+ } catch {
+ await message.reply("❌ Error finding message.");
- if (!channelMatch) {
- await message.reply(
- "❌ Please mention a channel or provide a message ID. Example: `#general` or `1234567890123456789`",
- );
+ return;
+ }
+ } else {
+ const channelMatch = firstParameter.match(/<#(\d+)>/);
- return;
- }
+ if (!channelMatch) {
+ await message.reply(
+ "❌ Please mention a channel or provide a message ID. Example: `#general` or `1234567890123456789`",
+ );
- const channelId = channelMatch[1];
+ return;
+ }
- targetChannel = message.client.channels.cache.get(channelId);
+ const channelId = channelMatch[1];
- if (!targetChannel || !targetChannel.isTextBased()) {
- await message.reply("❌ Channel not found or is not a text channel.");
+ targetChannel = message.client.channels.cache.get(channelId);
- return;
- }
+ if (!targetChannel || !targetChannel.isTextBased()) {
+ await message.reply("❌ Channel not found or is not a text channel.");
+
+ return;
}
+ }
- try {
- await message.delete();
-
- const baseDuration = Math.max(1, messageContent.length / 20);
- const complexityMultiplier =
- (messageContent.match(/[.!?]/g) || []).length * 0.5;
- const wordCount = messageContent.split(" ").length;
- const wordComplexityMultiplier = Math.min(wordCount / 10, 2);
- const typingDuration = Math.min(
- baseDuration + complexityMultiplier + wordComplexityMultiplier,
- 8,
- );
+ try {
+ await message.delete();
+
+ const baseDuration = Math.max(1, messageContent.length / 20);
+ const complexityMultiplier =
+ (messageContent.match(/[.!?]/g) || []).length * 0.5;
+ const wordCount = messageContent.split(" ").length;
+ const wordComplexityMultiplier = Math.min(wordCount / 10, 2);
+ const typingDuration = Math.min(
+ baseDuration + complexityMultiplier + wordComplexityMultiplier,
+ 8,
+ );
+
+ await (targetChannel as any).sendTyping();
+ await new Promise((resolve) =>
+ setTimeout(resolve, typingDuration * 1000),
+ );
+
+ if (targetMessage) {
+ await targetMessage.reply(messageContent);
+ } else {
+ await (targetChannel as any).send(messageContent);
+ }
+ } catch (error) {
+ console.error("Error executing say command:", error);
- await (targetChannel as any).sendTyping();
- await new Promise((resolve) =>
- setTimeout(resolve, typingDuration * 1000),
+ try {
+ await message.reply(
+ "❌ Failed to execute the say command. Please check permissions.",
);
-
- if (targetMessage) {
- await targetMessage.reply(messageContent);
- } else {
- await (targetChannel as any).send(messageContent);
- }
- } catch (error) {
- console.error("Error executing say command:", error);
-
- try {
- await message.reply(
- "❌ Failed to execute the say command. Please check permissions.",
- );
- } catch (replyError) {
- console.error("Failed to send error reply:", replyError);
- }
+ } catch (replyError) {
+ console.error("Failed to send error reply:", replyError);
}
}
+ }
};
diff --git a/packages/gateway/src/commands/start.ts b/packages/gateway/src/commands/start.ts
index b6c9300..9b8beb5 100644
--- a/packages/gateway/src/commands/start.ts
+++ b/packages/gateway/src/commands/start.ts
@@ -2,80 +2,78 @@ import { Message } from "discord.js";
import { sendProgressUpdate, executeBulkRoleAssignment } from "./utilities";
export const handleStartCommand = async (message: Message) => {
- if (message.author.bot) return;
+ if (message.author.bot) return;
- if (message.content.toLowerCase().startsWith("uma!start")) {
- const application = await message.client.application?.fetch();
- const ownerId = application?.owner?.id;
+ if (message.content.toLowerCase().startsWith("uma!start")) {
+ const application = await message.client.application?.fetch();
+ const ownerId = application?.owner?.id;
- if (message.author.id !== ownerId) return;
+ if (message.author.id !== ownerId) return;
- const parameters = message.content.split(" ").slice(1);
+ const parameters = message.content.split(" ").slice(1);
- if (parameters.length < 3) {
- await message.reply(
- "❌ Usage: `uma!start <role_mention> <channel_mention_or_category_id> <update_channel_id> [action]`\nExample: `uma!start @Participant #general 1415599617214513254 execute`",
- );
-
- return;
- }
-
- const roleMention = parameters[0];
- const channelOrCategory = parameters[1];
- const updateChannelId = parameters[2];
- const action = parameters[3] || "execute";
- const roleMatch = roleMention.match(/<@&(\d+)>/);
+ if (parameters.length < 3) {
+ await message.reply(
+ "❌ Usage: `uma!start <role_mention> <channel_mention_or_category_id> <update_channel_id> [action]`\nExample: `uma!start @Participant #general 1415599617214513254 execute`",
+ );
- if (!roleMatch) {
- await message.reply(
- "❌ Please mention a role. Example: `@Participant`",
- );
+ return;
+ }
- return;
- }
+ const roleMention = parameters[0];
+ const channelOrCategory = parameters[1];
+ const updateChannelId = parameters[2];
+ const action = parameters[3] || "execute";
+ const roleMatch = roleMention.match(/<@&(\d+)>/);
- const roleId = roleMatch[1];
- let channelId: string | undefined;
- let categoryId: string | undefined;
- const channelMatch = channelOrCategory.match(/<#(\d+)>/);
+ if (!roleMatch) {
+ await message.reply("❌ Please mention a role. Example: `@Participant`");
- if (channelMatch) {
- channelId = channelMatch[1];
- } else {
- categoryId = channelOrCategory;
- }
+ return;
+ }
- if (action !== "preview" && action !== "execute") {
- await message.reply("❌ Action must be either `preview` or `execute`");
+ const roleId = roleMatch[1];
+ let channelId: string | undefined;
+ let categoryId: string | undefined;
+ const channelMatch = channelOrCategory.match(/<#(\d+)>/);
- return;
- }
+ if (channelMatch) {
+ channelId = channelMatch[1];
+ } else {
+ categoryId = channelOrCategory;
+ }
- if (action === "preview") {
- await message.reply(
- "📋 Preview mode - this would check the specified channel(s) for users who have sent messages.",
- );
+ if (action !== "preview" && action !== "execute") {
+ await message.reply("❌ Action must be either `preview` or `execute`");
- return;
- }
+ return;
+ }
+ if (action === "preview") {
await message.reply(
- "🚀 Bulk role operation started! Check the progress channel for updates.",
+ "📋 Preview mode - this would check the specified channel(s) for users who have sent messages.",
);
- executeBulkRoleAssignment(
+ return;
+ }
+
+ await message.reply(
+ "🚀 Bulk role operation started! Check the progress channel for updates.",
+ );
+
+ executeBulkRoleAssignment(
+ message.client,
+ roleId,
+ updateChannelId,
+ channelId,
+ categoryId,
+ ).catch((error) => {
+ console.error("Bulk role assignment failed:", error);
+ sendProgressUpdate(
message.client,
- roleId,
+ "❌ Bulk role assignment failed due to an error",
updateChannelId,
- channelId,
- categoryId,
- ).catch((error) => {
- console.error("Bulk role assignment failed:", error);
- sendProgressUpdate(
- message.client,
- "❌ Bulk role assignment failed due to an error",
- updateChannelId,
- );
- });
- }
+ );
+ });
+ }
};
diff --git a/packages/gateway/src/commands/utilities.ts b/packages/gateway/src/commands/utilities.ts
index bc9892d..7aa49f0 100644
--- a/packages/gateway/src/commands/utilities.ts
+++ b/packages/gateway/src/commands/utilities.ts
@@ -591,7 +591,6 @@ export const executeBulkRoleAssignment = async (
if (error.code === 10007 || error.message?.includes("Unknown Member")) {
notInGuildCount += 1;
-
} else {
errorCount += 1;
}
diff --git a/packages/gateway/src/listeners/announcementReaction.ts b/packages/gateway/src/listeners/announcementReaction.ts
index 7a498b6..e0c12ce 100644
--- a/packages/gateway/src/listeners/announcementReaction.ts
+++ b/packages/gateway/src/listeners/announcementReaction.ts
@@ -3,13 +3,13 @@ import { Message } from "discord.js";
const ANNOUNCEMENT_CHANNEL_ID = "1406591215608270981";
export const handleAnnouncementReaction = async (message: Message) => {
- if (message.channelId !== ANNOUNCEMENT_CHANNEL_ID) return;
+ if (message.channelId !== ANNOUNCEMENT_CHANNEL_ID) return;
- if (message.author.id === message.client.user?.id) return;
+ if (message.author.id === message.client.user?.id) return;
- try {
- await message.react("1406426721158303864");
- } catch (error) {
- console.error("Failed to add okbuddy reaction to announcement:", error);
- }
+ try {
+ await message.react("1406426721158303864");
+ } catch (error) {
+ console.error("Failed to add okbuddy reaction to announcement:", error);
+ }
};
diff --git a/packages/gateway/src/listeners/artMediaModeration.ts b/packages/gateway/src/listeners/artMediaModeration.ts
index 48fdc55..73208c6 100644
--- a/packages/gateway/src/listeners/artMediaModeration.ts
+++ b/packages/gateway/src/listeners/artMediaModeration.ts
@@ -5,40 +5,40 @@ import {
} from "./constants";
export const handleArtMediaModeration = async (message: Message) => {
- if (message.channelId !== ART_MEDIA_NSFW_CHANNEL_ID) return;
+ if (message.channelId !== ART_MEDIA_NSFW_CHANNEL_ID) return;
- try {
- if (message.author.id === message.client.user?.id) return;
+ try {
+ if (message.author.id === message.client.user?.id) return;
- const hasMediaAttachments = message.attachments.some((attachment) => {
- const contentType = attachment.contentType;
+ const hasMediaAttachments = message.attachments.some((attachment) => {
+ const contentType = attachment.contentType;
- return (
- contentType?.startsWith("image/") ||
- contentType?.startsWith("video/") ||
- contentType?.startsWith("audio/")
- );
- });
+ return (
+ contentType?.startsWith("image/") ||
+ contentType?.startsWith("video/") ||
+ contentType?.startsWith("audio/")
+ );
+ });
- if (hasMediaAttachments) return;
+ if (hasMediaAttachments) return;
- await message.delete();
+ await message.delete();
- const errorMessage = await (message.channel as any).send(
- `${message.author}, only media can go in this channel. NSFW discussion should be kept in <#${NSFW_DISCUSSION_CHANNEL_ID}>.\n\nThis message will be deleted in 30 seconds.`,
- );
+ const errorMessage = await (message.channel as any).send(
+ `${message.author}, only media can go in this channel. NSFW discussion should be kept in <#${NSFW_DISCUSSION_CHANNEL_ID}>.\n\nThis message will be deleted in 30 seconds.`,
+ );
- setTimeout(async () => {
- try {
- await errorMessage.delete();
- } catch (error) {
- console.error(
- "Failed to delete art media moderation error message:",
- error,
- );
- }
- }, 30000);
- } catch (error) {
- console.error("Error in art media moderation:", error);
- }
+ setTimeout(async () => {
+ try {
+ await errorMessage.delete();
+ } catch (error) {
+ console.error(
+ "Failed to delete art media moderation error message:",
+ error,
+ );
+ }
+ }, 30000);
+ } catch (error) {
+ console.error("Error in art media moderation:", error);
+ }
};
diff --git a/packages/gateway/src/listeners/clientReady.ts b/packages/gateway/src/listeners/clientReady.ts
index 99e8af8..1b790ab 100644
--- a/packages/gateway/src/listeners/clientReady.ts
+++ b/packages/gateway/src/listeners/clientReady.ts
@@ -9,9 +9,6 @@ export const handleClientReady = (client: Client) => {
const channel = client.channels.cache.get(ROLEPLAY_UMAGRAM_CHANNEL_ID);
if (channel && channel.isTextBased()) {
-
- let totalMessageCount = 0;
- let totalHeartCount = 0;
const processChannelMessages = async (
targetChannel: any,
channelName: string,
@@ -58,17 +55,10 @@ export const handleClientReady = (client: Client) => {
await new Promise((resolve) => setTimeout(resolve, 500));
}
-
return { messageCount, heartCount };
};
- const mainResult = await processChannelMessages(
- channel,
- "Main Channel",
- );
-
- totalMessageCount += mainResult.messageCount;
- totalHeartCount += mainResult.heartCount;
+ await processChannelMessages(channel, "Main Channel");
try {
const activeThreads = await (channel as any).threads?.fetchActive();
@@ -80,16 +70,9 @@ export const handleClientReady = (client: Client) => {
...archivedThreads.threads.values(),
];
-
for (const thread of allThreads) {
try {
- const threadResult = await processChannelMessages(
- thread,
- `Thread: ${thread.name}`,
- );
-
- totalMessageCount += threadResult.messageCount;
- totalHeartCount += threadResult.heartCount;
+ await processChannelMessages(thread, `Thread: ${thread.name}`);
} catch (error) {
console.error(`Error processing thread ${thread.name}:`, error);
}
@@ -97,7 +80,6 @@ export const handleClientReady = (client: Client) => {
} catch (error) {
console.error("Error fetching threads:", error);
}
-
}
} catch (error) {
console.error("Error adding hearts to existing messages:", error);
diff --git a/packages/gateway/src/listeners/iqdbModeration.ts b/packages/gateway/src/listeners/iqdbModeration.ts
index 2266497..fb1c640 100644
--- a/packages/gateway/src/listeners/iqdbModeration.ts
+++ b/packages/gateway/src/listeners/iqdbModeration.ts
@@ -7,218 +7,216 @@ const IQDB_MODERATION_CHANNEL_IDS = [
];
export const handleIqdbModeration = async (message: Message) => {
- if (!IQDB_MODERATION_CHANNEL_IDS.includes(message.channelId)) return;
-
- const imageAttachments = message.attachments.filter((attachment) =>
- attachment.contentType?.startsWith("image/"),
- );
-
- if (imageAttachments.size === 0) return;
-
- try {
-
- for (const attachment of imageAttachments.values()) {
- try {
- const { searchPic } = await import("iqdb-client");
- const result = await searchPic(attachment.url, { lib: "www" });
- const matches =
- result.data?.filter(
- (item) => item.similarity !== null && item.similarity > 0.75,
- ) || [];
-
- if (matches.length === 0) {
- continue;
- }
+ if (!IQDB_MODERATION_CHANNEL_IDS.includes(message.channelId)) return;
+
+ const imageAttachments = message.attachments.filter((attachment) =>
+ attachment.contentType?.startsWith("image/"),
+ );
+
+ if (imageAttachments.size === 0) return;
+
+ try {
+ for (const attachment of imageAttachments.values()) {
+ try {
+ const { searchPic } = await import("iqdb-client");
+ const result = await searchPic(attachment.url, { lib: "www" });
+ const matches =
+ result.data?.filter(
+ (item) => item.similarity !== null && item.similarity > 0.75,
+ ) || [];
+
+ if (matches.length === 0) {
+ continue;
+ }
- for (const match of matches) {
- if (match.sourceUrl) {
- try {
- let booruType = "";
- if (match.sourceUrl.includes("danbooru.donmai.us")) {
- booruType = "danbooru";
- } else if (match.sourceUrl.includes("yande.re")) {
- booruType = "yande.re";
- } else if (match.sourceUrl.includes("gelbooru.com")) {
- booruType = "gelbooru";
- } else if (match.sourceUrl.includes("konachan.com")) {
- booruType = "konachan";
- }
+ for (const match of matches) {
+ if (match.sourceUrl) {
+ try {
+ let booruType = "";
+ if (match.sourceUrl.includes("danbooru.donmai.us")) {
+ booruType = "danbooru";
+ } else if (match.sourceUrl.includes("yande.re")) {
+ booruType = "yande.re";
+ } else if (match.sourceUrl.includes("gelbooru.com")) {
+ booruType = "gelbooru";
+ } else if (match.sourceUrl.includes("konachan.com")) {
+ booruType = "konachan";
+ }
- if (booruType) {
+ if (booruType) {
+ try {
+ const postId = match.sourceUrl.match(/\/(\d+)/)?.[1];
- try {
- const postId = match.sourceUrl.match(/\/(\d+)/)?.[1];
+ if (!postId) continue;
- if (!postId) continue;
+ let tags: string[] = [];
- let tags: string[] = [];
+ if (booruType === "danbooru") {
+ const response = await fetch(
+ `https://danbooru.donmai.us/posts/${postId}.json`,
+ );
- if (booruType === "danbooru") {
- const response = await fetch(
- `https://danbooru.donmai.us/posts/${postId}.json`,
- );
+ if (response.ok) {
+ const postData = await response.json();
- if (response.ok) {
- const postData = await response.json();
+ tags = postData.tag_string?.split(" ") || [];
+ }
+ } else if (booruType === "yande.re") {
+ const response = await fetch(
+ `https://yande.re/post.json?tags=id:${postId}`,
+ );
- tags = postData.tag_string?.split(" ") || [];
- }
- } else if (booruType === "yande.re") {
- const response = await fetch(
- `https://yande.re/post.json?tags=id:${postId}`,
- );
+ if (response.ok) {
+ const postData = await response.json();
- if (response.ok) {
- const postData = await response.json();
+ if (postData.length > 0)
+ tags = postData[0].tags?.split(" ") || [];
+ }
+ } else if (booruType === "gelbooru") {
+ const response = await fetch(
+ `https://gelbooru.com/index.php?page=dapi&s=post&q=index&json=1&id=${postId}`,
+ );
- if (postData.length > 0)
- tags = postData[0].tags?.split(" ") || [];
- }
- } else if (booruType === "gelbooru") {
- const response = await fetch(
- `https://gelbooru.com/index.php?page=dapi&s=post&q=index&json=1&id=${postId}`,
- );
+ if (response.ok) {
+ const postData = await response.json();
- if (response.ok) {
- const postData = await response.json();
+ if (postData.post)
+ tags = postData.post.tags?.split(" ") || [];
+ }
+ } else if (booruType === "konachan") {
+ const response = await fetch(
+ `https://konachan.com/post.json?tags=id:${postId}`,
+ );
- if (postData.post)
- tags = postData.post.tags?.split(" ") || [];
- }
- } else if (booruType === "konachan") {
- const response = await fetch(
- `https://konachan.com/post.json?tags=id:${postId}`,
- );
+ if (response.ok) {
+ const postData = await response.json();
- if (response.ok) {
- const postData = await response.json();
+ if (postData.length > 0)
+ tags = postData[0].tags?.split(" ") || [];
+ }
+ }
- if (postData.length > 0)
- tags = postData[0].tags?.split(" ") || [];
+ const prohibitedTags = [
+ /^(loli|shota)$/i,
+ /^(loli|shota)_/i,
+ /_(loli|shota)$/i,
+ /_(loli|shota)_/i,
+ ];
+ const foundProhibitedTags = tags.filter((tag) =>
+ prohibitedTags.some((prohibited) => {
+ if (prohibited instanceof RegExp) {
+ return prohibited.test(tag);
+ } else {
+ return tag
+ .toLowerCase()
+ .includes((prohibited as string).toLowerCase());
}
- }
+ }),
+ );
+ if (foundProhibitedTags.length > 0) {
+ const similarity = match.similarity!;
+ const isHighConfidence = similarity > 0.75;
- const prohibitedTags = [
- /^(loli|shota)$/i,
- /^(loli|shota)_/i,
- /_(loli|shota)$/i,
- /_(loli|shota)_/i,
- ];
- const foundProhibitedTags = tags.filter((tag) =>
- prohibitedTags.some((prohibited) => {
- if (prohibited instanceof RegExp) {
- return prohibited.test(tag);
- } else {
- return tag
- .toLowerCase()
- .includes((prohibited as string).toLowerCase());
- }
- }),
+ console.warn(
+ `Prohibited tags detected: ${foundProhibitedTags.join(", ")}, similarity: ${(similarity * 100).toFixed(1)}%, ${isHighConfidence ? "deleting message" : "sending notification"}`,
);
- if (foundProhibitedTags.length > 0) {
- const similarity = match.similarity!;
- const isHighConfidence = similarity > 0.75;
-
- console.warn(
- `Prohibited tags detected: ${foundProhibitedTags.join(", ")}, similarity: ${(similarity * 100).toFixed(1)}%, ${isHighConfidence ? "deleting message" : "sending notification"}`,
- );
-
- const { EmbedBuilder } = await import("discord.js");
- const embed = new EmbedBuilder()
- .setTitle(
- isHighConfidence
- ? "🚫 Image Deleted - Prohibited Tags Detected"
- : "⚠️ Potential Prohibited Content Detected",
- )
- .setColor(isHighConfidence ? "#ff0000" : "#ffaa00")
- .addFields(
- {
- name: "Channel",
- value: `<#${message.channelId}>`,
- inline: true,
- },
- {
- name: "Author",
- value: `<@${message.author.id}>`,
- inline: true,
- },
- {
- name: "Message ID",
- value: `[${message.id}](https://discord.com/channels/${message.guildId}/${message.channelId}/${message.id})`,
- inline: true,
- },
- {
- name: "Booru Source",
- value: `[${booruType}](${match.sourceUrl})`,
- inline: true,
- },
- {
- name: "Similarity",
- value: `${(similarity * 100).toFixed(1)}%`,
- inline: true,
- },
- {
- name: "Prohibited Tags",
- value: foundProhibitedTags.join(", "),
- inline: false,
- },
- )
- .setTimestamp()
- .setFooter({
- text: `Guild: ${message.guild?.name || "Unknown"}`,
+ const { EmbedBuilder } = await import("discord.js");
+ const embed = new EmbedBuilder()
+ .setTitle(
+ isHighConfidence
+ ? "🚫 Image Deleted - Prohibited Tags Detected"
+ : "⚠️ Potential Prohibited Content Detected",
+ )
+ .setColor(isHighConfidence ? "#ff0000" : "#ffaa00")
+ .addFields(
+ {
+ name: "Channel",
+ value: `<#${message.channelId}>`,
+ inline: true,
+ },
+ {
+ name: "Author",
+ value: `<@${message.author.id}>`,
+ inline: true,
+ },
+ {
+ name: "Message ID",
+ value: `[${message.id}](https://discord.com/channels/${message.guildId}/${message.channelId}/${message.id})`,
+ inline: true,
+ },
+ {
+ name: "Booru Source",
+ value: `[${booruType}](${match.sourceUrl})`,
+ inline: true,
+ },
+ {
+ name: "Similarity",
+ value: `${(similarity * 100).toFixed(1)}%`,
+ inline: true,
+ },
+ {
+ name: "Prohibited Tags",
+ value: foundProhibitedTags.join(", "),
+ inline: false,
+ },
+ )
+ .setTimestamp()
+ .setFooter({
+ text: `Guild: ${message.guild?.name || "Unknown"}`,
+ });
+
+ if (isHighConfidence) await message.delete();
+
+ try {
+ const channelId = "1406422619934167106";
+ const channel =
+ message.client.channels.cache.get(channelId);
+
+ if (channel && "send" in channel) {
+ const imageResponse = await fetch(attachment.url);
+ const imageBuffer = await imageResponse.arrayBuffer();
+ const imageAttachment = {
+ attachment: Buffer.from(imageBuffer),
+ name: attachment.name || "flagged_image.jpg",
+ };
+
+ await (channel as any).send({
+ embeds: [embed],
+ files: [imageAttachment],
});
-
- if (isHighConfidence) await message.delete();
-
- try {
- const channelId = "1406422619934167106";
- const channel = message.client.channels.cache.get(channelId);
-
- if (channel && "send" in channel) {
- const imageResponse = await fetch(attachment.url);
- const imageBuffer = await imageResponse.arrayBuffer();
- const imageAttachment = {
- attachment: Buffer.from(imageBuffer),
- name: attachment.name || "flagged_image.jpg",
- };
-
- await (channel as any).send({
- embeds: [embed],
- files: [imageAttachment],
- });
- }
- } catch (error) {
- console.error("Error sending image attachment:", error);
-
- await sendAuditLog(
- message.client,
- embed,
- undefined,
- "1406422619934167106",
- );
}
-
- return;
+ } catch (error) {
+ console.error("Error sending image attachment:", error);
+
+ await sendAuditLog(
+ message.client,
+ embed,
+ undefined,
+ "1406422619934167106",
+ );
}
- } catch (error) {
- console.error(
- `Error fetching tags from ${booruType}:`,
- error,
- );
+
+ return;
}
+ } catch (error) {
+ console.error(
+ `Error fetching tags from ${booruType}:`,
+ error,
+ );
}
- } catch (error) {
- console.error("Error processing booru match:", error);
}
+ } catch (error) {
+ console.error("Error processing booru match:", error);
}
}
- } catch (error) {
- console.error("Error processing image attachment:", error);
}
+ } catch (error) {
+ console.error("Error processing image attachment:", error);
}
- } catch (error) {
- console.error("Error in iqdb moderation:", error);
}
+ } catch (error) {
+ console.error("Error in iqdb moderation:", error);
+ }
};
diff --git a/packages/gateway/src/listeners/moderationAgent/index.ts b/packages/gateway/src/listeners/moderationAgent/index.ts
index 7c7c170..d1e7f7e 100644
--- a/packages/gateway/src/listeners/moderationAgent/index.ts
+++ b/packages/gateway/src/listeners/moderationAgent/index.ts
@@ -1,10 +1,4 @@
-import {
- Client,
- Events,
- Message,
- TextChannel,
- ThreadChannel,
-} from "discord.js";
+import { Message, TextChannel, ThreadChannel } from "discord.js";
import { sendAuditLog } from "../../commands/utilities";
import {
EXCLUDED_CATEGORIES,
@@ -19,225 +13,218 @@ import {
import { analyzeMessageWithAI, fetchMessageContext } from "./utilities";
export const handleAIModeration = async (message: Message) => {
- if (message.author.bot) return;
+ if (message.author.bot) return;
+
+ if (!message.content && message.attachments.size === 0) return;
+
+ if (!message.content && message.attachments.size > 0) {
+ return;
+ }
- if (!message.content && message.attachments.size === 0) return;
+ if (message.content) {
+ const content = message.content.trim();
- if (!message.content && message.attachments.size > 0) {
+ if (!content) {
return;
}
- if (message.content) {
- const content = message.content.trim();
+ const shortWhitelist =
+ /^(ok|okay|yes|no|hi|hey|yo|lol|thanks|thx|np|cool)$/i;
- if (!content) {
- return;
- }
+ if (content.length < MIN_MESSAGE_LENGTH && !shortWhitelist.test(content)) {
+ return;
+ }
- const shortWhitelist =
- /^(ok|okay|yes|no|hi|hey|yo|lol|thanks|thx|np|cool)$/i;
+ const emojiRegExp =
+ /^(?:\p{Emoji_Presentation}|\p{Extended_Pictographic}|\s)+$/u;
- if (
- content.length < MIN_MESSAGE_LENGTH &&
- !shortWhitelist.test(content)
- ) {
- return;
- }
+ if (emojiRegExp.test(content)) {
+ return;
+ }
- const emojiRegExp =
- /^(?:\p{Emoji_Presentation}|\p{Extended_Pictographic}|\s)+$/u;
+ const symbolRegExp = /^[^\p{L}\p{N}\s]+$/u;
- if (emojiRegExp.test(content)) {
- return;
- }
+ if (symbolRegExp.test(content)) {
+ return;
+ }
- const symbolRegExp = /^[^\p{L}\p{N}\s]+$/u;
+ const symbolDensity =
+ content.replace(/[\p{L}\p{N}\s]/gu, "").length / content.length;
+
+ if (symbolDensity >= MAX_SYMBOL_DENSITY && content.length > 3) {
+ return;
+ }
- if (symbolRegExp.test(content)) {
+ for (const pattern of LOW_RISK_PATTERNS)
+ if (pattern.test(content)) {
return;
}
- const symbolDensity =
- content.replace(/[\p{L}\p{N}\s]/gu, "").length / content.length;
-
- if (symbolDensity >= MAX_SYMBOL_DENSITY && content.length > 3) {
+ if (content.length <= 20 && /^[a-zA-Z]+$/.test(content))
+ if (SAFE_WORDS.has(content.toLowerCase())) {
return;
}
-
- for (const pattern of LOW_RISK_PATTERNS)
- if (pattern.test(content)) {
- return;
- }
-
- if (content.length <= 20 && /^[a-zA-Z]+$/.test(content))
- if (SAFE_WORDS.has(content.toLowerCase())) {
- return;
- }
+ }
+
+ if (message.channel.isThread()) {
+ const parentChannel = message.channel.parent;
+
+ if (parentChannel && "parentId" in parentChannel && parentChannel.parentId)
+ if (EXCLUDED_CATEGORIES.includes(parentChannel.parentId)) return;
+ } else if ("parentId" in message.channel && message.channel.parentId) {
+ if (EXCLUDED_CATEGORIES.includes(message.channel.parentId)) return;
+ }
+
+ try {
+ const context = await fetchMessageContext(
+ message.channel as TextChannel | ThreadChannel,
+ message.id,
+ );
+ const analysis = await analyzeMessageWithAI(message, context);
+
+ if (!analysis) {
+ console.error("AI analysis failed, skipping moderation");
+ return;
}
- if (message.channel.isThread()) {
- const parentChannel = message.channel.parent;
-
- if (
- parentChannel &&
- "parentId" in parentChannel &&
- parentChannel.parentId
- )
- if (EXCLUDED_CATEGORIES.includes(parentChannel.parentId)) return;
- } else if ("parentId" in message.channel && message.channel.parentId) {
- if (EXCLUDED_CATEGORIES.includes(message.channel.parentId)) return;
+ if (!analysis.violation) {
+ return;
}
- try {
- const context = await fetchMessageContext(
- message.channel as TextChannel | ThreadChannel,
- message.id,
- );
- const analysis = await analyzeMessageWithAI(message, context);
-
- if (!analysis) {
- console.error("AI analysis failed, skipping moderation");
- return;
- }
-
- if (!analysis.violation) {
- return;
- }
+ console.warn(
+ `Rule violation detected: ${analysis.rule} (severity: ${analysis.severity}, confidence: ${analysis.confidence}%)`,
+ );
+ if (SKIP_ACTION) {
console.warn(
- `Rule violation detected: ${analysis.rule} (severity: ${analysis.severity}, confidence: ${analysis.confidence}%)`,
+ `SKIP_ACTION enabled - logging violation without taking action (severity: ${analysis.severity}, confidence: ${analysis.confidence}%)`,
);
+ } else if (
+ (analysis.severity === "critical" || analysis.severity === "high") &&
+ analysis.confidence >= 75
+ ) {
+ try {
+ await message.delete();
+ console.warn(`Auto-deleted high severity violation`);
- if (SKIP_ACTION) {
- console.warn(
- `SKIP_ACTION enabled - logging violation without taking action (severity: ${analysis.severity}, confidence: ${analysis.confidence}%)`,
- );
- } else if (
- (analysis.severity === "critical" || analysis.severity === "high") &&
- analysis.confidence >= 75
- ) {
try {
- await message.delete();
- console.warn(`Auto-deleted high severity violation`);
-
- try {
- const notificationText = `${message.author}, your message was deleted: **${analysis.brief}**. This notification will be deleted in 10 seconds.\n\nIf you believe this was a mistake, let me know in #umabot.`;
- const notificationMessage = await (message.channel as any).send(
- notificationText,
- );
-
- setTimeout(async () => {
- try {
- await notificationMessage.delete();
- } catch (error) {
- console.error("Failed to delete notification message:", error);
- }
- }, 10000);
- } catch (error) {
- console.error("Failed to send notification message:", error);
- }
+ const notificationText = `${message.author}, your message was deleted: **${analysis.brief}**. This notification will be deleted in 10 seconds.\n\nIf you believe this was a mistake, let me know in #umabot.`;
+ const notificationMessage = await (message.channel as any).send(
+ notificationText,
+ );
+
+ setTimeout(async () => {
+ try {
+ await notificationMessage.delete();
+ } catch (error) {
+ console.error("Failed to delete notification message:", error);
+ }
+ }, 10000);
} catch (error) {
- console.error("Failed to delete message:", error);
+ console.error("Failed to send notification message:", error);
}
- } else {
- console.warn(
- `Logging violation for human review (severity: ${analysis.severity}, confidence: ${analysis.confidence}%)`,
- );
+ } catch (error) {
+ console.error("Failed to delete message:", error);
}
+ } else {
+ console.warn(
+ `Logging violation for human review (severity: ${analysis.severity}, confidence: ${analysis.confidence}%)`,
+ );
+ }
- const { EmbedBuilder } = await import("discord.js");
- const wasDeleted =
- !SKIP_ACTION &&
- (analysis.severity === "critical" || analysis.severity === "high") &&
- analysis.confidence >= 85;
- const embed = new EmbedBuilder()
- .setTitle(
- wasDeleted
- ? "🤖 Message Deleted - Rule Violation"
- : "⚠️ Rule Violation Detected",
- )
- .setColor(
- analysis.severity === "critical"
- ? "#ff0000"
- : analysis.severity === "high"
- ? "#ff6600"
- : analysis.severity === "medium"
- ? "#ffaa00"
- : "#ffff00",
- )
- .addFields(
- {
- name: "Channel",
- value: `<#${message.channelId}>`,
- inline: true,
- },
- {
- name: "Author",
- value: `<@${message.author.id}>`,
- inline: true,
- },
- {
- name: "Message ID",
- value: `[${message.id}](https://discord.com/channels/${message.guildId}/${message.channelId}/${message.id})`,
- inline: true,
- },
- {
- name: "Rule Violation",
- value: analysis.rule,
- inline: false,
- },
- {
- name: "Severity",
- value: analysis.severity.toUpperCase(),
- inline: true,
- },
- {
- name: "Confidence",
- value: `${analysis.confidence}%`,
- inline: true,
- },
- {
- name: "Brief",
- value: analysis.brief,
- inline: false,
- },
- {
- name: "Explanation",
- value: analysis.explanation,
- inline: false,
- },
- )
- .setTimestamp()
- .setFooter({
- text: `Guild: ${message.guild?.name || "Unknown"}`,
- });
-
- if (message.content && message.content.length <= 1000)
- embed.addFields({
- name: wasDeleted ? "Deleted Message Content" : "Message Content",
- value: message.content,
+ const { EmbedBuilder } = await import("discord.js");
+ const wasDeleted =
+ !SKIP_ACTION &&
+ (analysis.severity === "critical" || analysis.severity === "high") &&
+ analysis.confidence >= 85;
+ const embed = new EmbedBuilder()
+ .setTitle(
+ wasDeleted
+ ? "🤖 Message Deleted - Rule Violation"
+ : "⚠️ Rule Violation Detected",
+ )
+ .setColor(
+ analysis.severity === "critical"
+ ? "#ff0000"
+ : analysis.severity === "high"
+ ? "#ff6600"
+ : analysis.severity === "medium"
+ ? "#ffaa00"
+ : "#ffff00",
+ )
+ .addFields(
+ {
+ name: "Channel",
+ value: `<#${message.channelId}>`,
+ inline: true,
+ },
+ {
+ name: "Author",
+ value: `<@${message.author.id}>`,
+ inline: true,
+ },
+ {
+ name: "Message ID",
+ value: `[${message.id}](https://discord.com/channels/${message.guildId}/${message.channelId}/${message.id})`,
+ inline: true,
+ },
+ {
+ name: "Rule Violation",
+ value: analysis.rule,
inline: false,
- });
-
- if (!SKIP_PRIMARY_NOTIFICATION)
- await sendAuditLog(
- message.client,
- embed,
- message.content && message.content.length > 1000
- ? message.content
- : undefined,
- MODERATION_LOG_CHANNEL_ID,
- );
-
+ },
+ {
+ name: "Severity",
+ value: analysis.severity.toUpperCase(),
+ inline: true,
+ },
+ {
+ name: "Confidence",
+ value: `${analysis.confidence}%`,
+ inline: true,
+ },
+ {
+ name: "Brief",
+ value: analysis.brief,
+ inline: false,
+ },
+ {
+ name: "Explanation",
+ value: analysis.explanation,
+ inline: false,
+ },
+ )
+ .setTimestamp()
+ .setFooter({
+ text: `Guild: ${message.guild?.name || "Unknown"}`,
+ });
+
+ if (message.content && message.content.length <= 1000)
+ embed.addFields({
+ name: wasDeleted ? "Deleted Message Content" : "Message Content",
+ value: message.content,
+ inline: false,
+ });
+
+ if (!SKIP_PRIMARY_NOTIFICATION)
await sendAuditLog(
message.client,
embed,
message.content && message.content.length > 1000
? message.content
: undefined,
- "1420931142600757280",
+ MODERATION_LOG_CHANNEL_ID,
);
- } catch (error) {
- console.error("Error in AI moderation:", error);
- }
+
+ await sendAuditLog(
+ message.client,
+ embed,
+ message.content && message.content.length > 1000
+ ? message.content
+ : undefined,
+ "1420931142600757280",
+ );
+ } catch (error) {
+ console.error("Error in AI moderation:", error);
+ }
};
diff --git a/packages/gateway/src/listeners/moderationAgent/utilities.ts b/packages/gateway/src/listeners/moderationAgent/utilities.ts
index 3e94e71..ec3201f 100644
--- a/packages/gateway/src/listeners/moderationAgent/utilities.ts
+++ b/packages/gateway/src/listeners/moderationAgent/utilities.ts
@@ -324,7 +324,6 @@ Remember: Only enforce the exact rules provided. Do not make assumptions or inte
const data = await response.json();
-
const content = data.choices[0]?.message?.content;
if (!content) {
diff --git a/packages/gateway/src/listeners/roleMentionCooldown.ts b/packages/gateway/src/listeners/roleMentionCooldown.ts
index a4e9a0b..d1fba37 100644
--- a/packages/gateway/src/listeners/roleMentionCooldown.ts
+++ b/packages/gateway/src/listeners/roleMentionCooldown.ts
@@ -1,61 +1,64 @@
-import { Message, Role } from "discord.js";
+import { Message } from "discord.js";
-const COOLDOWN_ROLES = [
- "1421632398302515271",
- "1421632887219814572"
-];
+const COOLDOWN_ROLES = ["1421632398302515271", "1421632887219814572"];
const COOLDOWN_DURATION = 30 * 60 * 1000;
const roleCooldowns = new Map<string, number>();
export const handleRoleMentionCooldown = async (message: Message) => {
- if (message.author.bot) return;
+ if (message.author.bot) return;
- if (!message.guild) return;
+ if (!message.guild) return;
- const mentionedRoles = message.mentions.roles.filter(role =>
- COOLDOWN_ROLES.includes(role.id)
- );
+ const mentionedRoles = message.mentions.roles.filter((role) =>
+ COOLDOWN_ROLES.includes(role.id),
+ );
- if (mentionedRoles.size === 0) return;
+ if (mentionedRoles.size === 0) return;
- const now = Date.now();
+ const now = Date.now();
- for (const role of mentionedRoles.values()) {
- const cooldownEnd = roleCooldowns.get(role.id);
-
- if (cooldownEnd && now < cooldownEnd) {
- const timeLeft = Math.ceil((cooldownEnd - now) / 1000);
- const minutesLeft = Math.ceil(timeLeft / 60);
- const notification = await message.reply(
- `This role is on cooldown for ${minutesLeft} more minute(s). This notification will be deleted in 10 seconds.`
- );
+ for (const role of mentionedRoles.values()) {
+ const cooldownEnd = roleCooldowns.get(role.id);
- setTimeout(async () => {
- try {
- await notification.delete();
- } catch (error) {
- console.error("Failed to delete cooldown notification:", error);
- }
- }, 10000);
+ if (cooldownEnd && now < cooldownEnd) {
+ const timeLeft = Math.ceil((cooldownEnd - now) / 1000);
+ const minutesLeft = Math.ceil(timeLeft / 60);
+ const notification = await message.reply(
+ `This role is on cooldown for ${minutesLeft} more minute(s). This notification will be deleted in 10 seconds.`,
+ );
- return;
- }
+ setTimeout(async () => {
+ try {
+ await notification.delete();
+ } catch (error) {
+ console.error("Failed to delete cooldown notification:", error);
+ }
+ }, 10000);
+
+ return;
+ }
+
+ roleCooldowns.set(role.id, now + COOLDOWN_DURATION);
- roleCooldowns.set(role.id, now + COOLDOWN_DURATION);
+ try {
+ await role.setMentionable(false, "Role mention cooldown activated");
+ setTimeout(async () => {
try {
- await role.setMentionable(false, "Role mention cooldown activated");
-
- setTimeout(async () => {
- try {
- await role.setMentionable(true, "Role mention cooldown expired");
- roleCooldowns.delete(role.id);
- } catch (error) {
- console.error(`Failed to re-enable mention permissions for role ${role.name}:`, error);
- }
- }, COOLDOWN_DURATION);
+ await role.setMentionable(true, "Role mention cooldown expired");
+ roleCooldowns.delete(role.id);
} catch (error) {
- console.error(`Failed to disable mention permissions for role ${role.name}:`, error);
+ console.error(
+ `Failed to re-enable mention permissions for role ${role.name}:`,
+ error,
+ );
}
+ }, COOLDOWN_DURATION);
+ } catch (error) {
+ console.error(
+ `Failed to disable mention permissions for role ${role.name}:`,
+ error,
+ );
}
+ }
};
diff --git a/packages/gateway/src/listeners/roleplayUmagram.ts b/packages/gateway/src/listeners/roleplayUmagram.ts
index 9a2fa32..a60a1b6 100644
--- a/packages/gateway/src/listeners/roleplayUmagram.ts
+++ b/packages/gateway/src/listeners/roleplayUmagram.ts
@@ -2,44 +2,44 @@ import { Message } from "discord.js";
import { ROLEPLAY_UMAGRAM_CHANNEL_ID } from "./constants";
export const handleRoleplayUmagram = async (message: Message) => {
- const isMainChannel = message.channelId === ROLEPLAY_UMAGRAM_CHANNEL_ID;
- const isThreadInChannel =
- message.channel?.isThread() &&
- message.channel.parentId === ROLEPLAY_UMAGRAM_CHANNEL_ID;
+ const isMainChannel = message.channelId === ROLEPLAY_UMAGRAM_CHANNEL_ID;
+ const isThreadInChannel =
+ message.channel?.isThread() &&
+ message.channel.parentId === ROLEPLAY_UMAGRAM_CHANNEL_ID;
- if (!isMainChannel && !isThreadInChannel) return;
+ if (!isMainChannel && !isThreadInChannel) return;
- try {
- if (message.author.id === message.client.user?.id) return;
+ try {
+ if (message.author.id === message.client.user?.id) return;
- try {
- await message.react("❤️");
- } catch (error) {
- console.error("Failed to add heart reaction:", error);
- }
+ try {
+ await message.react("❤️");
+ } catch (error) {
+ console.error("Failed to add heart reaction:", error);
+ }
- if (isMainChannel && !message.reference) {
- const hasAttachments = message.attachments.size > 0;
- const hasTextContent =
- message.content && message.content.trim().split(/\s+/).length > 1;
-
- if (!hasAttachments || !hasTextContent) {
- await message.delete();
-
- const errorMessage = await (message.channel as any).send(
- `${message.author}, to participate in <#${ROLEPLAY_UMAGRAM_CHANNEL_ID}>, you can either:\n\n- **Post**: Send a message with both a brief caption **and** an image attachment\n- **Reply**: Reply to someone else's post (no image needed)\n - Reply with a thread (suggested)\n - Reply directly with a message\n\nThis message will be deleted in 30 seconds.`,
- );
-
- setTimeout(async () => {
- try {
- await errorMessage.delete();
- } catch (error) {
- console.error("Failed to delete error message:", error);
- }
- }, 30000);
- }
+ if (isMainChannel && !message.reference) {
+ const hasAttachments = message.attachments.size > 0;
+ const hasTextContent =
+ message.content && message.content.trim().split(/\s+/).length > 1;
+
+ if (!hasAttachments || !hasTextContent) {
+ await message.delete();
+
+ const errorMessage = await (message.channel as any).send(
+ `${message.author}, to participate in <#${ROLEPLAY_UMAGRAM_CHANNEL_ID}>, you can either:\n\n- **Post**: Send a message with both a brief caption **and** an image attachment\n- **Reply**: Reply to someone else's post (no image needed)\n - Reply with a thread (suggested)\n - Reply directly with a message\n\nThis message will be deleted in 30 seconds.`,
+ );
+
+ setTimeout(async () => {
+ try {
+ await errorMessage.delete();
+ } catch (error) {
+ console.error("Failed to delete error message:", error);
+ }
+ }, 30000);
}
- } catch (error) {
- console.error("Error in roleplay-umagram moderation:", error);
}
+ } catch (error) {
+ console.error("Error in roleplay-umagram moderation:", error);
+ }
};