From 62356142ac1691409149cd02e5fee64bf23f12ee Mon Sep 17 00:00:00 2001 From: Matheus Albino Date: Sun, 3 Nov 2024 12:06:17 -0300 Subject: [PATCH] Refactoring and bugfixes --- src/bot.ts | 16 ++++ src/functions/attemptReplyAuthorMessage.ts | 56 +++++++----- src/functions/checkMessagesArrayReposts.ts | 33 ------- src/functions/deleteRepliesToAuthorMessage.ts | 5 ++ src/functions/handleMessageReposts.ts | 24 ++--- src/functions/handleMessageUpdate.ts | 8 ++ src/functions/orderMessagesArrayByPostDate.ts | 17 ++++ src/utils/url.ts | 87 ++++++++++++------- 8 files changed, 152 insertions(+), 94 deletions(-) delete mode 100644 src/functions/checkMessagesArrayReposts.ts create mode 100644 src/functions/deleteRepliesToAuthorMessage.ts create mode 100644 src/functions/handleMessageUpdate.ts create mode 100644 src/functions/orderMessagesArrayByPostDate.ts diff --git a/src/bot.ts b/src/bot.ts index 322c9f4..c58f5c4 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -4,6 +4,8 @@ import { readyHandler } from "./functions/ready.ts"; import feedMessagesArray from "./functions/feedMessagesArray.ts"; import handleMessageReposts from "./functions/handleMessageReposts.ts"; import deleteMessageFromMessagesArray from "./functions/deleteMessageFromMessagesArray.ts"; +import handleMessageUpdate from "./functions/handleMessageUpdate.ts"; +import deleteRepliesToAuthorMessage from "./functions/deleteRepliesToAuthorMessage.ts"; const client = new Client({ intents: [ @@ -15,17 +17,31 @@ const client = new Client({ let messagesArr: Message[]; +let botIsReady = false; + client.once(Events.ClientReady, async (client) => { readyHandler(client); messagesArr = await feedMessagesArray(client); + botIsReady = true; }); client.on(Events.MessageCreate, async (message) => { + if (!botIsReady) return; + messagesArr = handleMessageReposts(messagesArr, message); }); +client.on(Events.MessageUpdate, async (message) => { + if (!botIsReady) return; + + messagesArr = handleMessageUpdate(messagesArr, message); // TODO +}); + client.on(Events.MessageDelete, async (message) => { + if (!botIsReady) return; + messagesArr = deleteMessageFromMessagesArray(messagesArr, message); + deleteRepliesToAuthorMessage(message); // TODO }); await client.login(process.env.DISCORD_TOKEN); diff --git a/src/functions/attemptReplyAuthorMessage.ts b/src/functions/attemptReplyAuthorMessage.ts index f99150e..5427e85 100644 --- a/src/functions/attemptReplyAuthorMessage.ts +++ b/src/functions/attemptReplyAuthorMessage.ts @@ -1,33 +1,47 @@ import { TextChannel, type Message } from "discord.js"; import { italic, underline } from "../utils/message.ts"; +import orderMessagesArrayByPostDate from "./orderMessagesArrayByPostDate.ts"; export default function attemptReplyAuthorMessage( - authorMessage: Message, - url: string, - originalMessages: Message[], + authorMessage: Message, + url: string, + originalMessages: Message[], ): void { - if (!(authorMessage.channel instanceof TextChannel)) return; - if (!authorMessage.guild) return; + if (!(authorMessage.channel instanceof TextChannel)) return; + if (!authorMessage.guild) return; - let replyMessage = `Hey! [${underline("O link que voce mandou")}](<${url}>) ja foi mandado no passado! Voce eh um repostado!`; + let replyMessage = `Hey! [${underline("O link que voce mandou")}](<${url}>) ja foi mandado no passado! Voce eh um repostado!`; - for (let index = 0; index < originalMessages.length; index++) { - const msg = originalMessages[index]; - if (!msg) return; + const sortedOriginalMessages = orderMessagesArrayByPostDate(originalMessages); - const { id, guildId, channelId, author } = msg; + for (let index = 0; index < sortedOriginalMessages.length; index++) { + const message = sortedOriginalMessages[index]; + if (!message) return; - if (!author.globalName) return; + const { id, guildId, channelId, author } = message; - const messageUrl = `https://discord.com/channels/${guildId}/${channelId}/${id}`; - replyMessage += `\n- Mensagem original ${++index} (por ${italic(author.globalName)}): ${messageUrl}`; - } + if (!author.globalName) return; - authorMessage - .reply({ - content: replyMessage, - options: { ephemeral: true }, - }) - .then() - .catch((_) => null); + const authorName = `"${author.globalName}"`; + + const msgNumber = index.toString().padStart(2, "0"); + + const messageUrl = `https://discord.com/channels/${guildId}/${channelId}/${id}`; + + let messageTemplateStart = "Postador original"; + + if (index !== 0) { + messageTemplateStart = `Repost numero ${msgNumber}`; + } + + replyMessage += `\n- ${messageTemplateStart} (por ${italic(authorName)}): ${messageUrl}`; + } + + authorMessage + .reply({ + content: replyMessage, + options: { ephemeral: true }, + }) + .then() + .catch((_) => null); } diff --git a/src/functions/checkMessagesArrayReposts.ts b/src/functions/checkMessagesArrayReposts.ts deleted file mode 100644 index 3b85cc7..0000000 --- a/src/functions/checkMessagesArrayReposts.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { Message } from "discord.js"; -import type MessageInfoWithReposts from "../interfaces/MessageInfoWithReposts.ts"; -import { transformMessageArrayInMap } from "../utils/message.ts"; - -export default function checkMessagesArrayForReposts( - messagesArray: Message[], -): Map { - const urlMessagesMap = transformMessageArrayInMap(messagesArray); - - const messageInfoWithRepostsMap = new Map(); - - for (const [url, messagesMentioningUrlArray] of urlMessagesMap) { - if (messagesMentioningUrlArray.length === 1) continue; - - const originalMessage = messagesMentioningUrlArray.reduce((prev, curr) => - prev.createdTimestamp < curr.createdTimestamp ? prev : curr, - ); - - const messageInfoWithRepostsMapPosition = - messageInfoWithRepostsMap.get(url); - - if (!messageInfoWithRepostsMapPosition) { - messageInfoWithRepostsMap.set(url, { - originalMessage, - repetitions: messagesMentioningUrlArray.filter( - (elm) => elm !== originalMessage, - ), - }); - } - } - - return messageInfoWithRepostsMap; -} diff --git a/src/functions/deleteRepliesToAuthorMessage.ts b/src/functions/deleteRepliesToAuthorMessage.ts new file mode 100644 index 0000000..b493232 --- /dev/null +++ b/src/functions/deleteRepliesToAuthorMessage.ts @@ -0,0 +1,5 @@ +import type { Message, PartialMessage } from "discord.js"; + +export default function deleteRepliesToAuthorMessage( + authorMessage: Message | PartialMessage, +): void { } diff --git a/src/functions/handleMessageReposts.ts b/src/functions/handleMessageReposts.ts index 2e4b665..9805e90 100644 --- a/src/functions/handleMessageReposts.ts +++ b/src/functions/handleMessageReposts.ts @@ -6,22 +6,24 @@ import updateMessagesArray from "./updateMessagesArray.ts"; import attemptReplyAuthorMessage from "./attemptReplyAuthorMessage.ts"; export default function handleMessageReposts( - messagesArray: Message[], - newMessage: Message, + messagesArray: Message[], + newMessage: Message, ): Message[] { - const urlMessagesMap = transformMessageArrayInMap(messagesArray); + const urlMessagesMap = transformMessageArrayInMap(messagesArray); - const newMessageClearedUrl = clearUrl(newMessage.content); + const newMessageClearedUrl = clearUrl(newMessage.content); - if (!newMessageClearedUrl) return messagesArray; + if (!newMessageClearedUrl) return messagesArray; - const originalMessages = urlMessagesMap.get(newMessageClearedUrl); + const originalMessages = urlMessagesMap.get(newMessageClearedUrl); - if (!originalMessages) { - return updateMessagesArray(messagesArray, newMessage); - } + const newMessagesArray = updateMessagesArray(messagesArray, newMessage); - attemptReplyAuthorMessage(newMessage, newMessageClearedUrl, originalMessages); + if (!originalMessages) { + return newMessagesArray; + } - return messagesArray; + attemptReplyAuthorMessage(newMessage, newMessageClearedUrl, originalMessages); + + return newMessagesArray; } diff --git a/src/functions/handleMessageUpdate.ts b/src/functions/handleMessageUpdate.ts new file mode 100644 index 0000000..7ea7f98 --- /dev/null +++ b/src/functions/handleMessageUpdate.ts @@ -0,0 +1,8 @@ +import type { Message, PartialMessage } from "discord.js"; + +export default function handleMessageUpdate( + messagesArray: Message[], + updatedMessage: Message | PartialMessage, +): Message[] { + return messagesArray; +} diff --git a/src/functions/orderMessagesArrayByPostDate.ts b/src/functions/orderMessagesArrayByPostDate.ts new file mode 100644 index 0000000..92b8936 --- /dev/null +++ b/src/functions/orderMessagesArrayByPostDate.ts @@ -0,0 +1,17 @@ +import type { Message } from "discord.js"; + +function compareMessageByTimestamp(prevMessage: Message, currMessage: Message) { + if (prevMessage.createdTimestamp < currMessage.createdTimestamp) { + return -1; + } + if (prevMessage.createdTimestamp > currMessage.createdTimestamp) { + return 1; + } + return 0; +} + +export default function orderMessagesArrayByPostDate( + messagesArray: Message[], +): Message[] { + return messagesArray.sort(compareMessageByTimestamp); +} diff --git a/src/utils/url.ts b/src/utils/url.ts index b583bbf..33da6cb 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -1,42 +1,71 @@ +type HostnameMap = { + [key: string]: string[]; +}; + +type DomainMap = { + [key: string]: string; +}; + +const HOSTNAME_MAPPINGS: HostnameMap = { + x: ["fixupx", "vxx"], + reddit: ["rxddit"], + bsky: ["bskye"], +}; + +const DOMAIN_ENDINGS: DomainMap = { + twitter: "x", + "vm.tiktok": "vm.tiktok", + tiktok: "tiktok", + instagram: "instagram", +}; + +const getHostnameReplacement = (cleanHostname: string): string => { + // Check for exact matches first - now searching through values to find the key + const exactMatch = Object.entries(HOSTNAME_MAPPINGS).find( + ([_, possibleNames]) => possibleNames.includes(cleanHostname), + ); + + if (exactMatch) { + return exactMatch[0]; // Return the key (replacement value) + } + + // Check domain endings + return ( + Object.entries(DOMAIN_ENDINGS).find(([ending]) => + cleanHostname.endsWith(ending), + )?.[1] ?? "" + ); +}; + export function clearUrl(url: string): string { - const urlRegex = /(https?:\/\/[^ ]*)/; + const urlRegex = /(https?:\/\/[^ ]*)/; - const matchUrl = url.match(urlRegex); + const matchUrl = url.match(urlRegex); - if (!matchUrl) return ""; - if (!matchUrl[0]) return ""; + if (!matchUrl) return ""; + if (!matchUrl[0]) return ""; - let clearedUrl = matchUrl[0].split("?")[0]; + let clearedUrl = matchUrl[0].split("?")[0]; - if (!clearedUrl) return ""; + if (!clearedUrl) return ""; - clearedUrl = clearedUrl.split("\n")[0]; + clearedUrl = clearedUrl.split("\n")[0]; - if (!clearedUrl) return ""; + if (!clearedUrl) return ""; - clearedUrl = clearedUrl.replace(/\/+$/, ""); + clearedUrl = clearedUrl.replace(/\/+$/, ""); - const { hostname } = new URL(clearedUrl); - const cleanHostname = hostname.substring( - hostname.indexOf(".") + 1, - hostname.lastIndexOf("."), - ); + const { hostname } = new URL(clearedUrl); + const cleanHostname = hostname.substring( + hostname.indexOf(".") + 1, + hostname.lastIndexOf("."), + ); - let hostnameReplaceStr = ""; + const hostnameReplaceStr = getHostnameReplacement(cleanHostname); - if (cleanHostname === "fixupx" || cleanHostname.endsWith("twitter")) { - hostnameReplaceStr = "x"; - } else if (cleanHostname.endsWith("vm.tiktok")) { - hostnameReplaceStr = "vm.tiktok"; - } else if (cleanHostname.endsWith("tiktok")) { - hostnameReplaceStr = "tiktok"; - } else if (cleanHostname.endsWith("instagram")) { - hostnameReplaceStr = "instagram"; - } + if (hostnameReplaceStr) { + clearedUrl = clearedUrl.replace(cleanHostname, hostnameReplaceStr); + } - if (hostnameReplaceStr) { - clearedUrl = clearedUrl.replace(cleanHostname, hostnameReplaceStr); - } - - return clearedUrl; + return clearedUrl; }