v0.1
This commit is contained in:
parent
a0c9bbfe9a
commit
d5e23f5033
2
default.env
Normal file
2
default.env
Normal file
|
@ -0,0 +1,2 @@
|
|||
TOKEN = 0 # Your bot token
|
||||
CLIENT_ID = 0 # Your bot client ID
|
1227
package-lock.json
generated
Normal file
1227
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
Normal file
18
package.json
Normal 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
21
src/config.ts
Normal 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
12
src/entry.ts
Normal 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
133
src/index.ts
Normal 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
42
src/modal/configure.ts
Normal 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
20
tsconfig.json
Normal 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"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user