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