-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.js
141 lines (115 loc) · 4.44 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
require('dotenv').config();
const Discord = require('discord.js');
const client = new Discord.Client({ intents: [Discord.Intents.FLAGS.GUILDS, Discord.Intents.FLAGS.GUILD_MESSAGES] });
const alphabetMap = require('./alphabet.js');
const REACT_MESSAGE_MAX_LENGTH = 20; // Maximum reactions allowed by Discord
const COMMAND_NAME = 'react';
console.log('discord-react-words startup');
const commandData = {
name: COMMAND_NAME,
description: 'Spells the given text with reaction emojis',
options: [{
name: 'input',
type: 'STRING',
description: 'Text to be printed with reaction',
required: true,
}
// TODO: Accept message ID or relative message index to react to
]
};
client.once('ready', async () => {
console.log('Discord.js client ready');
client.application.commands.create(commandData);
client.user.setActivity('/'+COMMAND_NAME, { type: 'LISTENING' });
});
if (process.env.TOKEN) {
client.login(process.env.TOKEN);
}
else {
console.log('TOKEN needs to be provided in environment variable');
process.exit(1);
}
client.on('interactionCreate', async (interaction) => {
console.log('interactionCreate fired. User: '+interaction.user.tag ?? 'unknown#xxxx');
if (!interaction.isCommand()) {
console.log('Received interaction that was not a command');
return;
}
if (!interaction.inGuild()) {
console.log('Received interaction outside of guild');
interaction.reply('Sorry, commands sent outside of servers are not supported');
return;
}
if (interaction.commandName !== COMMAND_NAME) {
console.log('Received interaction with invalid command name: '+interaction.commandName);
interaction.reply({ content: 'Unknown command', ephemeral: true });
return;
}
let input = interaction.options.get('input').value; // Required, so should not be null
console.log('Received /'+COMMAND_NAME+' interaction with input: '+input);
let reactions = tryConvertToReactions(input);
let message = (await interaction.channel?.messages?.fetch({ limit: 1 }))?.last(); // Grab the last message in the channel
if (message && reactions) {
interaction.reply({ content: 'Reactions on the way!', ephemeral: true });
console.log('Emoji conversion and message fetch successful: '+reactions);
console.log('Starting to add reactions');
for (const r of reactions) {
var err = false;
await message.react(r).catch((reason) => {
err = true;
});
if (err) {
console.log('Error while adding reactions');
break;
}
}
console.log('Finished adding reactions');
}
else {
let reason = 'Unknown reason';
if (!reactions) {
reason = 'Could not convert input to emoji';
}
else if (!message) {
reason = 'Could not fetch previous message';
}
console.log('Failed reaction: '+reason);
interaction.reply({ content: 'Failed to react: '+reason, ephemeral: true });
}
});
function tryConvertToReactions(inText) {
// TODO: Unicode normalizing
if (inText.length > REACT_MESSAGE_MAX_LENGTH) {
return null;
}
var text = inText.toLowerCase(); // TODO: English only for now :(
// Check text to ensure:
// 1. Each letter is in our alphabet
// 2. We have enough of each character in the alphabet
var letterCount = countCharacters(text);
for (const elem of letterCount) {
let char = elem[0];
let charCount = elem[1];
if (!alphabetMap.has(char) || alphabetMap.get(char).length < charCount) {
return null;
}
}
var reactions = [];
var alphabetIndexMap = new Map(); // Keep track of the number of each letter used, so we can iterate over the options for each
for (var i = 0; i < text.length; i++) {
let char = text.charAt(i);
let charIndex = alphabetIndexMap.get(char) ?? 0;
reactions.push(alphabetMap.get(char)[charIndex]);
// Increment the amount of the letter, or initialize to 1
alphabetIndexMap.set(char, (alphabetIndexMap.get(char) ?? 0) + 1);
}
return reactions;
}
// TODO: Not sure how safe this would be with non-English
function countCharacters(string) {
var count = new Map();
string.split('').forEach(function(s) {
count.set(s, (count.get(s) ?? 0) + 1);
});
return count;
}