diff options
Diffstat (limited to 'packages/gateway/src')
| -rw-r--r-- | packages/gateway/src/commands/crp.ts | 128 | ||||
| -rw-r--r-- | packages/gateway/src/commands/react.ts | 45 | ||||
| -rw-r--r-- | packages/gateway/src/commands/say.ts | 176 | ||||
| -rw-r--r-- | packages/gateway/src/commands/start.ts | 114 | ||||
| -rw-r--r-- | packages/gateway/src/commands/utilities.ts | 1 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/announcementReaction.ts | 14 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/artMediaModeration.ts | 58 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/clientReady.ts | 22 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/iqdbModeration.ts | 366 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/moderationAgent/index.ts | 367 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/moderationAgent/utilities.ts | 1 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/roleMentionCooldown.ts | 87 | ||||
| -rw-r--r-- | packages/gateway/src/listeners/roleplayUmagram.ts | 68 |
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); + } }; |