/[sudobot]/branches/7.x/src/commands/tools/ExtractEmojiCommand.ts
ViewVC logotype

Contents of /branches/7.x/src/commands/tools/ExtractEmojiCommand.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (show annotations)
Mon Jul 29 18:52:37 2024 UTC (8 months ago) by rakinar2
File MIME type: application/typescript
File size: 5481 byte(s)
chore: add old version archive branches (2.x to 9.x-dev)
1 /**
2 * This file is part of SudoBot.
3 *
4 * Copyright (C) 2021-2023 OSN Developers.
5 *
6 * SudoBot is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * SudoBot is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 import { EmbedBuilder, SlashCommandBuilder, parseEmoji } from "discord.js";
21 import Command, { ArgumentType, BasicCommandContext, CommandMessage, CommandReturn, ValidationRule } from "../../core/Command";
22 import { safeChannelFetch, safeMessageFetch } from "../../utils/fetch";
23
24 export default class ExtractEmojiCommand extends Command {
25 public readonly name = "extractemoji";
26 public readonly validationRules: ValidationRule[] = [
27 {
28 types: [ArgumentType.Link],
29 name: "message_link",
30 errors: {
31 required: "Please provide a message link to extract emoji from!",
32 "type:invalid": "Invalid message link given!"
33 }
34 }
35 ];
36 public readonly permissions = [];
37 public readonly aliases = ["getemojis", "extractemojis", "getemojis"];
38 public readonly description = "Extracts server emoji links from the given message.";
39 public readonly argumentSyntaxes = ["<message_link>"];
40 public readonly slashCommandBuilder = new SlashCommandBuilder().addStringOption(option =>
41 option.setName("message_link").setDescription("Link to the target message").setRequired(true)
42 );
43
44 extract(content: string) {
45 const emojis = [];
46 const regexMatches = [...content.matchAll(/(<a?:[\w_]+:\d+>)/gim)].map(match => match[0]);
47
48 for (const match of regexMatches) {
49 const parsed = parseEmoji(match);
50
51 if (!parsed?.id) {
52 continue;
53 }
54
55 emojis.push({
56 ...parsed,
57 url: `https://cdn.discordapp.com/emojis/${encodeURIComponent(parsed.id)}.${parsed.animated ? "gif" : "png"}`
58 });
59 }
60
61 return emojis;
62 }
63
64 async execute(message: CommandMessage, context: BasicCommandContext): Promise<CommandReturn> {
65 await this.deferIfInteraction(message);
66
67 const link = context.isLegacy ? context.parsedNamedArgs.message_link : context.options.getString("message_link", true);
68
69 if (!/^https?:\/\/(canary\.|ptb\.|beta\.|www\.|)discord\.com\/channels\/\d+\/\d+\/\d+$/i.test(link.trim())) {
70 await this.error(message, this.validationRules[0].errors!["type:invalid"]!);
71 return;
72 }
73
74 const [messageId, channelId, guildId] = link
75 .substring(0, link[link.length - 1] === "/" ? link.length - 1 : link.length)
76 .split("/")
77 .reverse();
78
79 if (guildId !== message.guildId!) {
80 await this.error(message, "That's a message link from another server!");
81 return;
82 }
83
84 const channel = await safeChannelFetch(message.guild!, channelId);
85
86 if (!channel) {
87 await this.error(message, "The link is invalid, couldn't find the specified channel!");
88 return;
89 }
90
91 if (!channel.isTextBased()) {
92 await this.error(message, "The link points to a non-text based channel!");
93 return;
94 }
95
96 const targetMessage = await safeMessageFetch(channel, messageId);
97
98 if (!targetMessage) {
99 await this.error(
100 message,
101 "The link is invalid, couldn't find the specified message! Make sure that it wasn't deleted."
102 );
103 return;
104 }
105
106 const parsedEmojis = this.extract(targetMessage.content);
107
108 for (const embed of targetMessage.embeds) {
109 if (embed.description) {
110 parsedEmojis.push(...this.extract(embed.description));
111 }
112
113 for (const field of embed.fields) {
114 if (field.value) {
115 parsedEmojis.push(...this.extract(field.value));
116 }
117 }
118 }
119
120 const emojis: typeof parsedEmojis = [];
121
122 for (const emoji of parsedEmojis) {
123 if (!!emojis.find(e => e.id === emoji.id)) {
124 continue;
125 }
126
127 emojis.push(emoji);
128 }
129
130 if (emojis.length === 0) {
131 await this.error(message, "Could not find any server-based emoji in the given message.");
132 return;
133 }
134
135 let description = "";
136
137 for (const { name, url, animated } of emojis) {
138 description += `* [${name}](${url})${animated ? " (Animated)" : ""}\n`;
139 }
140
141 await this.deferredReply(message, {
142 embeds: [
143 new EmbedBuilder({
144 title: "Extracted Emojis",
145 color: 0x007bff,
146 description,
147 footer: {
148 text: `Extracted ${emojis.length} emojis total`
149 }
150 }).setTimestamp()
151 ]
152 });
153 }
154 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26