-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.js
More file actions
256 lines (224 loc) · 8.76 KB
/
index.js
File metadata and controls
256 lines (224 loc) · 8.76 KB
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// Load environment variables from the .env file
require('dotenv').config();
// Import necessary Discord.js classes
const { Client, GatewayIntentBits, REST, Routes, SlashCommandBuilder, ButtonStyle, ActionRowBuilder, ButtonBuilder } = require('discord.js');
const axios = require('axios');
// Import objects and options from external files
const objects = require('./list.js'); // Contains direct URL queries
const options = require('./options.js'); // Contains queries requiring user input
// Create the bot client instance
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
]
});
// Define slash commands
const commands = [
new SlashCommandBuilder()
.setName('search')
.setDescription('Search for an object')
.addStringOption(option =>
option.setName('query')
.setDescription('The name to search for')
.setRequired(true)),
new SlashCommandBuilder()
.setName('socials')
.setDescription('Get our social media links'),
new SlashCommandBuilder()
.setName('help')
.setDescription('Get help with using the bot'),
new SlashCommandBuilder()
.setName('chuck')
.setDescription('Get a random Chuck Norris joke')
];
// Set up REST API instance
const rest = new REST({ version: '10' }).setToken(process.env.TOKEN);
// Register commands when the bot is ready
client.once('ready', async () => {
console.log('Bot is ready!');
try {
console.log('Registering slash commands.');
await rest.put(
Routes.applicationCommands(client.user.id),
{ body: commands }
);
console.log('Slash commands registered successfully.');
} catch (error) {
console.error('Error registering slash commands:', error);
}
});
// Handle interactions
client.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) return;
try {
switch (interaction.commandName) {
case 'help':
const helpMessage = `Available commands:
/help - Get help with using the bot
/chuck - Get a random Chuck Norris joke
/search - Search for an object
/socials - Get our social media links`;
await interaction.reply({
content: helpMessage,
flags: ['Ephemeral'] // Sends the help message as ephemeral (only the user sees it)
});
break;
case 'chuck':
// Handle the chuck command
await interaction.deferReply();
try {
const response = await axios.get('https://api.chucknorris.io/jokes/random');
await interaction.editReply(response.data.value);
} catch (error) {
console.error('Chuck Norris API error:', error);
await interaction.followUp({
content: "Sorry, couldn't fetch a joke right now. Please try again later.",
flags: ['Ephemeral']
});
}
break;
case 'search':
// Handle the search command
const query = interaction.options.getString('query');
// Find if the query matches any direct URL
let res = objects.filter(item => item.name.toLowerCase() === query.toLowerCase());
if (res.length > 0) {
// If direct match is found, send URL
await interaction.reply({
content: `You selected: ${res[0].name}. Here's the link: ${res[0].URL}`,
flags: 64 // Ephemeral flag
});
return;
}
// Find if the query matches any options-based search
let optionsRes = options.find(item => item.name.toLowerCase() === query.toLowerCase());
if (optionsRes) {
// Send buttons for the user to choose
let response = `Please choose an option from the list below:\n`;
// Create an ActionRowBuilder with ButtonBuilder components
const row = new ActionRowBuilder().addComponents(
optionsRes.options.map((option, index) =>
new ButtonBuilder()
.setCustomId(`option_${index + 1}`)
.setLabel(option.name)
.setStyle(ButtonStyle.Primary)
)
);
// Send the options with buttons
const message = await interaction.reply({
content: response,
components: [row],
flags: 64, // Ephemeral flag
});
// Listen for the button click event
const filter = i => i.user.id === interaction.user.id && i.isButton();
const collector = interaction.channel.createMessageComponentCollector({ filter, time: 30000 });
collector.on('collect', async i => {
// Ignore the button click if the user already responded
if (i.replied) return;
const buttonIndex = parseInt(i.customId.split('_')[1]) - 1;
const selectedOption = optionsRes.options[buttonIndex];
// Respond with the selected option and its link
if (selectedOption.URL) {
await i.reply({
content: `You selected: ${selectedOption.name}. Here's the link: ${selectedOption.URL}`,
flags: 64 // Ephemeral flag
});
} else {
await i.reply({
content: `You selected: ${selectedOption.name}. No URL available.`,
flags: 64 // Ephemeral flag
});
}
// Disable the buttons after the user selects one
const disabledRow = new ActionRowBuilder().addComponents(
optionsRes.options.map((option, index) =>
new ButtonBuilder()
.setCustomId(`disabled_${index + 1}`) // Ensure custom_id is still included
.setLabel('Option Disabled')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true)
)
);
// Edit the original message with disabled buttons
await message.edit({
content: `You selected: ${selectedOption.name}. Here's the link: ${selectedOption.URL || 'No URL available.'}`,
components: [disabledRow],
});
// Stop the collector right away after responding
collector.stop();
});
collector.on('end', async (collected, reason) => {
if (reason === 'time') {
const timeoutMessage = `Hey ${interaction.user}, looks like you took too long to respond!`;
await interaction.followUp({
content: timeoutMessage,
flags: 64 // Ephemeral flag
});
}
// Only disable the buttons and update the message if no response was collected
if (reason === 'time') {
const disabledRow = new ActionRowBuilder().addComponents(
optionsRes.options.map((option, index) =>
new ButtonBuilder()
.setCustomId(`disabled_${index + 1}`)
.setLabel('Option Disabled')
.setStyle(ButtonStyle.Secondary)
.setDisabled(true)
)
);
try {
await message.edit({
content: "You took too long to respond. The options are now disabled.",
components: [disabledRow],
});
} catch (error) {
console.error('Error editing message:', error);
}
}
});
} else {
await interaction.reply({
content: `No matching object found for "${query}".`,
flags: 64 // Ephemeral flag
});
}
break;
case 'socials':
// Handle the socials command
const socialLinks = [
{ name: 'Linktree', url: 'https://linktr.ee/snailsnft' },
{ name: 'Medium', url: 'https://medium.com/@snailsnft/' },
{ name: 'OmniFlix', url: 'https://omniflix.tv/channel/65182782e1c28773aa199c84' },
{ name: 'YouTube', url: 'https://www.youtube.com/@SNAILS._/videos' }
];
let response = 'Here are our social media links:\n';
socialLinks.forEach(link => {
response += `${link.name}: ${link.url}\n`;
});
await interaction.reply({
content: response,
flags: 64 // Ephemeral flag
});
break;
default:
break;
}
} catch (error) {
console.error(`Error handling ${interaction.commandName} command:`, error);
await interaction.reply({
content: "An error occurred. Please try again later.",
flags: ['Ephemeral']
});
}
});
// Error handling for client
client.on('error', error => {
console.error('Discord client error:', error);
});
// Log in the bot using the token
client.login(process.env.TOKEN).catch(error => {
console.error('Error logging in:', error);
});