This commit is contained in:
Keisuke Hirata 2024-09-09 04:28:10 +09:00
parent a0c9bbfe9a
commit d5e23f5033
8 changed files with 1475 additions and 0 deletions

2
default.env Normal file
View File

@ -0,0 +1,2 @@
TOKEN = 0 # Your bot token
CLIENT_ID = 0 # Your bot client ID

1227
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

18
package.json Normal file
View File

@ -0,0 +1,18 @@
{
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
},
"type": "module",
"dependencies": {
"discord.js": "^14.16.1",
"dotenv": "^16.4.5"
},
"devDependencies": {
"@types/node": "^22.5.4",
"tsx": "^4.19.0",
"typescript": "^5.5.4"
}
}

21
src/config.ts Normal file
View File

@ -0,0 +1,21 @@
import fs from 'fs';
import { Entry } from './entry.ts';
export function writeConfig(entries: Entry[]) {
const data = JSON.stringify(entries, null, 2);
fs.writeFile('./config.json', data, (err) => {
if (err) {
console.error(err);
return;
}
});
}
export function readConfig(): Entry[] {
if (!fs.existsSync('./config.json')) {
return [];
}
const data = fs.readFileSync('./config.json', 'utf8');
return JSON.parse(data);
}

12
src/entry.ts Normal file
View File

@ -0,0 +1,12 @@
export class Entry {
server: string;
channel: string;
emoji: string;
count: number;
constructor(server: string, channel: string, emoji: string, count: number) {
this.server = server;
this.channel = channel;
this.emoji = emoji;
this.count = count;
}
}

133
src/index.ts Normal file
View File

@ -0,0 +1,133 @@
import {
REST,
Routes,
Client,
Partials,
GatewayIntentBits,
Events,
} from "discord.js";
import { writeConfig, readConfig } from "./config.ts";
import 'dotenv/config'
const TOKEN = process.env.TOKEN;
const CLIENT_ID = process.env.CLIENT_ID;
if (!TOKEN) {
console.error("No token provided");
process.exit();
}
if (!CLIENT_ID) {
console.error("No client ID provided");
process.exit();
}
const rest = new REST({ version: "10" }).setToken(TOKEN);
try {
console.log("refreshing slash commands...");
await rest.put(Routes.applicationCommands(CLIENT_ID), {
body: [
{
name: "config",
description: "Replies with the channel ID",
},
],
});
console.log("OK");
} catch (error) {
console.error(error);
}
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMessageReactions,
],
partials: [Partials.Message, Partials.Channel, Partials.Reaction],
});
client.on("ready", () => {
if (!client.user) return;
console.log(`Logged in as ${client.user.tag}!`);
});
import { Entry } from "./entry.ts";
const entries: Entry[] = readConfig();
import modal from "./modal/configure.ts";
client.on("interactionCreate", async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === "config") {
await interaction.showModal(modal);
}
});
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isModalSubmit()) return;
if (interaction.customId === "config") {
const emoji = interaction.fields.getTextInputValue("emoji");
const count = parseInt(interaction.fields.getTextInputValue("count"));
const channelId = interaction.fields.getTextInputValue("channelId");
const serverId = interaction.guildId;
if (!emoji || !channelId) {
await interaction.reply({
content: "Please fill out all fields",
ephemeral: true,
});
return;
}
if (serverId === null) {
return;
}
console.log(`Set entry: ${serverId} -> ${channelId} (${emoji})`);
const entry = entries.find((entry) => entry.server === serverId);
if (entry) {
entry.channel = channelId;
entry.emoji = emoji;
entry.count = count;
} else {
entries.push(new Entry(serverId, channelId, emoji, count));
}
writeConfig(entries);
await interaction.reply({
content: `Set to send messages to <#${channelId}>, watching for ${emoji}`,
ephemeral: true,
});
}
});
client.on(Events.MessageReactionAdd, async (reaction, user) => {
if (reaction.partial) {
try {
await reaction.fetch();
} catch (error) {
console.error("Something went wrong when fetching the message:", error);
return;
}
}
if (!reaction.message.guild) return;
const entry = entries.find(
(entry) => entry.server === reaction.message.guildId
);
if (
!entry ||
reaction.emoji.name !== entry.emoji ||
reaction.count === null ||
reaction.count < entry.count
)
return;
const channel = await client.channels.fetch(entry.channel);
if (channel === null || !channel.isTextBased() || channel.isDMBased()) return;
if (reaction.count === entry.count) {
await channel.send(
`🎉 ${reaction.count} people have reacted with ${entry.emoji}! 🎉`
);
}
});
client.login(TOKEN);

42
src/modal/configure.ts Normal file
View File

@ -0,0 +1,42 @@
import {
ModalBuilder,
TextInputBuilder,
ActionRowBuilder,
TextInputStyle,
ModalActionRowComponentBuilder,
} from 'discord.js';
const modal = new ModalBuilder()
.setCustomId('config')
.setTitle('Configuration');
const emojiInput = new TextInputBuilder()
.setCustomId('emoji')
.setLabel('Emoji')
.setStyle(TextInputStyle.Short)
.setPlaceholder('Enter the emoji')
.setValue('⭐')
.setRequired(true);
const countInput = new TextInputBuilder()
.setCustomId('count')
.setLabel('Count')
.setStyle(TextInputStyle.Short)
.setPlaceholder('Enter the count')
.setValue('5')
.setRequired(true);
const channelIdInput = new TextInputBuilder()
.setCustomId('channelId')
.setLabel('Channel ID')
.setStyle(TextInputStyle.Short)
.setPlaceholder('Enter the channel ID')
.setRequired(true);
const first = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(emojiInput)
const second = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(countInput)
const third = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(channelIdInput)
modal.addComponents(first, second, third);
export default modal;

20
tsconfig.json Normal file
View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": [
"ES2023"
],
"module": "node16",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true,
"outDir": "./dist",
},
"include": [
"src/**/*.ts"
]
}