Initial commit of karuta-starboard bot
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
.env
|
||||||
|
db.json
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
|
||||||
|
const { getMessages } = require('../utils/configManager');
|
||||||
|
const { setGuildData } = require('../utils/dbManager');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('setemoji')
|
||||||
|
.setDescription('Set the reaction emoji')
|
||||||
|
.addStringOption(option =>
|
||||||
|
option.setName('emoji')
|
||||||
|
.setDescription('Emoji (ex: ⭐ or <:name:id> or <a:name:id>)')
|
||||||
|
.setRequired(true))
|
||||||
|
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator),
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
const emoji = interaction.options.getString('emoji');
|
||||||
|
setGuildData(interaction.guildId, { emoji });
|
||||||
|
|
||||||
|
const messages = getMessages();
|
||||||
|
if (!messages.emoji_set_success) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: '❌ Missing `emoji_set_success` message in config.yml.',
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const reply = messages.emoji_set_success.replace('{emoji}', emoji);
|
||||||
|
await interaction.reply({ content: reply, ephemeral: true });
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
|
||||||
|
const { getMessages } = require('../utils/configManager');
|
||||||
|
const { setGuildData } = require('../utils/dbManager');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data: new SlashCommandBuilder()
|
||||||
|
.setName('setstarboard')
|
||||||
|
.setDescription('Set up the highlight channel')
|
||||||
|
.addChannelOption(option =>
|
||||||
|
option.setName('channel')
|
||||||
|
.setDescription('Select the channel for highlighted messages')
|
||||||
|
.setRequired(true))
|
||||||
|
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild),
|
||||||
|
|
||||||
|
async execute(interaction) {
|
||||||
|
const channel = interaction.options.getChannel('channel');
|
||||||
|
setGuildData(interaction.guildId, { starboard: channel.id });
|
||||||
|
|
||||||
|
const messages = getMessages();
|
||||||
|
if (!messages.starboard_set_success) {
|
||||||
|
return interaction.reply({
|
||||||
|
content: '❌ Missing `starboard_set_success` message in config.yml.',
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const reply = messages.starboard_set_success.replace('{channel}', `<#${channel.id}>`);
|
||||||
|
await interaction.reply({ content: reply, ephemeral: true });
|
||||||
|
}
|
||||||
|
};
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
messages:
|
||||||
|
error: "❌ An error occurred while executing the command."
|
||||||
|
emoji_set_success: "Emoji set: {emoji}"
|
||||||
|
starboard_set_success: "Channel set: {channel}"
|
||||||
|
embed_jump_text: "Click to jump to message!"
|
||||||
|
|
||||||
|
appearance:
|
||||||
|
embed_color: "#ff5733"
|
||||||
|
|
||||||
|
activity:
|
||||||
|
name: "Made by UltraLion"
|
||||||
|
type: "WATCHING" # PLAYING, LISTENING, COMPETING, WATCHING
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
const { REST, Routes } = require('discord.js');
|
||||||
|
const fs = require('fs');
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const commands = [];
|
||||||
|
const commandFiles = fs.readdirSync('./SlashCommands').filter(file => file.endsWith('.js'));
|
||||||
|
|
||||||
|
for (const file of commandFiles) {
|
||||||
|
const command = require(`./SlashCommands/${file}`);
|
||||||
|
commands.push(command.data.toJSON());
|
||||||
|
}
|
||||||
|
|
||||||
|
const rest = new REST({ version: '10' }).setToken(process.env.TOKEN);
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
console.log('⏳ Deploying slash commands...');
|
||||||
|
await rest.put(Routes.applicationCommands(process.env.CLIENT_ID), { body: commands });
|
||||||
|
console.log('✅ Commands deployed successfully.');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
module.exports = {
|
||||||
|
name: 'interactionCreate',
|
||||||
|
async execute(interaction) {
|
||||||
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
|
const command = interaction.client.commands.get(interaction.commandName);
|
||||||
|
if (!command) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await command.execute(interaction);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: '❌ Error executing command.',
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
const { EmbedBuilder } = require('discord.js');
|
||||||
|
const { getGuildData } = require('../utils/dbManager');
|
||||||
|
const { getMessages, getAppearance } = require('../utils/configManager');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'messageReactionAdd',
|
||||||
|
async execute(reaction, user) {
|
||||||
|
if (user.bot) return;
|
||||||
|
const message = reaction.message.partial ? await reaction.message.fetch() : reaction.message;
|
||||||
|
|
||||||
|
const guildConfig = getGuildData(message.guildId);
|
||||||
|
if (!guildConfig || !guildConfig.emoji || !guildConfig.starboard) return;
|
||||||
|
|
||||||
|
const usedEmoji = reaction.emoji.toString();
|
||||||
|
if (usedEmoji !== guildConfig.emoji) return;
|
||||||
|
|
||||||
|
if (!message.author?.bot || !message.author.username.includes('Karuta')) return;
|
||||||
|
|
||||||
|
const channel = await reaction.client.channels.fetch(guildConfig.starboard);
|
||||||
|
|
||||||
|
const messages = getMessages();
|
||||||
|
const appearance = getAppearance();
|
||||||
|
|
||||||
|
if (!messages.embed_jump_text || !appearance.embed_color) {
|
||||||
|
console.warn('⚠️ Missing config: embed_jump_text or embed_color');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const jumpLink = `https://discord.com/channels/${message.guildId}/${message.channelId}/${message.id}`;
|
||||||
|
const jumpText = messages.embed_jump_text;
|
||||||
|
const embedColor = parseInt(appearance.embed_color.replace('#', ''), 16);
|
||||||
|
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setDescription(`${message.content}\n\n[${jumpText}](${jumpLink})`)
|
||||||
|
.setColor(embedColor)
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
|
const attachment = message.attachments.find(att =>
|
||||||
|
att.contentType?.startsWith('image/') || att.contentType?.startsWith('video/')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (attachment) embed.setImage(attachment.url);
|
||||||
|
|
||||||
|
await channel.send({ embeds: [embed] });
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
const { ActivityType } = require('discord.js');
|
||||||
|
const { getActivity } = require('../utils/configManager');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'ready',
|
||||||
|
once: true,
|
||||||
|
execute(client) {
|
||||||
|
console.log(`✅ Logged in as ${client.user.tag}`);
|
||||||
|
|
||||||
|
const activity = getActivity();
|
||||||
|
if (!activity.name || !activity.type) {
|
||||||
|
console.warn('⚠️ Missing configuration for bot status in config.yml.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.user.setActivity(activity.name, {
|
||||||
|
type: ActivityType[activity.type.toUpperCase()]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
const { Client, GatewayIntentBits, Collection, Partials } = require('discord.js');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const client = new Client({
|
||||||
|
intents: [
|
||||||
|
GatewayIntentBits.Guilds,
|
||||||
|
GatewayIntentBits.GuildMessages,
|
||||||
|
GatewayIntentBits.MessageContent,
|
||||||
|
GatewayIntentBits.GuildMessageReactions
|
||||||
|
],
|
||||||
|
partials: [Partials.Message, Partials.Channel, Partials.Reaction]
|
||||||
|
});
|
||||||
|
|
||||||
|
client.commands = new Collection();
|
||||||
|
|
||||||
|
// Load commands
|
||||||
|
const commandsPath = path.join(__dirname, 'SlashCommands');
|
||||||
|
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
|
||||||
|
for (const file of commandFiles) {
|
||||||
|
const command = require(path.join(commandsPath, file));
|
||||||
|
client.commands.set(command.data.name, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load events
|
||||||
|
const eventsPath = path.join(__dirname, 'events');
|
||||||
|
const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js'));
|
||||||
|
for (const file of eventFiles) {
|
||||||
|
const event = require(path.join(eventsPath, file));
|
||||||
|
if (event.once) {
|
||||||
|
client.once(event.name, (...args) => event.execute(...args, client));
|
||||||
|
} else {
|
||||||
|
client.on(event.name, (...args) => event.execute(...args, client));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.login(process.env.TOKEN);
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/rest": "^2.5.1",
|
||||||
|
"csv-parser": "^3.2.0",
|
||||||
|
"discord-api-types": "^0.38.13",
|
||||||
|
"discord.js": "^14.20.0",
|
||||||
|
"dotenv": "^16.5.0",
|
||||||
|
"fs": "^0.0.1-security",
|
||||||
|
"node-fetch": "^3.3.2",
|
||||||
|
"yaml": "^2.8.0"
|
||||||
|
},
|
||||||
|
"name": "dabi",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
require('dotenv').config();
|
||||||
|
const { Client, GatewayIntentBits } = require('discord.js');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] });
|
||||||
|
|
||||||
|
|
||||||
|
const TOKEN = process.env.TOKEN;
|
||||||
|
const AVATAR_PATH = path.join(__dirname, 'assets', 'avatar.gif');
|
||||||
|
|
||||||
|
client.once('ready', async () => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Read GIF file
|
||||||
|
const avatar = fs.readFileSync(AVATAR_PATH);
|
||||||
|
|
||||||
|
// Set the avatar
|
||||||
|
await client.user.setAvatar(avatar);
|
||||||
|
console.log('Bot avatar successfully updated!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erreur de Discord :', error.response?.data || error);
|
||||||
|
console.error('Error updating bot avatar:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.login(TOKEN);
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const YAML = require('yaml');
|
||||||
|
|
||||||
|
const configPath = './config.yml';
|
||||||
|
|
||||||
|
function readConfig() {
|
||||||
|
try {
|
||||||
|
const file = fs.readFileSync(configPath, 'utf8');
|
||||||
|
return YAML.parse(file) || {};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error reading config.yml file:', error);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeConfig(config) {
|
||||||
|
try {
|
||||||
|
const yamlString = YAML.stringify(config);
|
||||||
|
fs.writeFileSync(configPath, yamlString, 'utf8');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error writing to config.yml:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessages() {
|
||||||
|
const config = readConfig();
|
||||||
|
return config.messages || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGuildConfig(guildId) {
|
||||||
|
const config = readConfig();
|
||||||
|
if (!config.guilds) config.guilds = {};
|
||||||
|
if (!config.guilds[guildId]) config.guilds[guildId] = {};
|
||||||
|
return config.guilds[guildId];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setGuildConfig(guildId, newData) {
|
||||||
|
const config = readConfig();
|
||||||
|
if (!config.guilds) config.guilds = {};
|
||||||
|
config.guilds[guildId] = {
|
||||||
|
...config.guilds[guildId],
|
||||||
|
...newData
|
||||||
|
};
|
||||||
|
writeConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAppearance() {
|
||||||
|
const config = readConfig();
|
||||||
|
return config.appearance || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActivity() {
|
||||||
|
const config = readConfig();
|
||||||
|
return config.activity || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
readConfig,
|
||||||
|
writeConfig,
|
||||||
|
getMessages,
|
||||||
|
getGuildConfig,
|
||||||
|
setGuildConfig,
|
||||||
|
getAppearance,
|
||||||
|
getActivity
|
||||||
|
};
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const dbPath = './db.json';
|
||||||
|
|
||||||
|
function readDB() {
|
||||||
|
try {
|
||||||
|
const data = fs.readFileSync(dbPath, 'utf8');
|
||||||
|
return JSON.parse(data) || {};
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeDB(data) {
|
||||||
|
fs.writeFileSync(dbPath, JSON.stringify(data, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGuildData(guildId) {
|
||||||
|
const db = readDB();
|
||||||
|
if (!db[guildId]) db[guildId] = {};
|
||||||
|
return db[guildId];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setGuildData(guildId, newData) {
|
||||||
|
const db = readDB();
|
||||||
|
db[guildId] = {
|
||||||
|
...db[guildId],
|
||||||
|
...newData
|
||||||
|
};
|
||||||
|
writeDB(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getGuildData,
|
||||||
|
setGuildData
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user