コードの分割とボイスチャンネルへの接続コマンドの追加

This commit is contained in:
ntki72 2024-11-07 00:08:14 +09:00
parent f3c2d6336a
commit b968a8f4bc
13 changed files with 224 additions and 15 deletions

5
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/discord_read_bot.iml" filepath="$PROJECT_DIR$/.idea/discord_read_bot.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,3 +1,4 @@
NODE_ENV=development NODE_ENV=development
LOG_LEVEL=debug LOG_LEVEL=debug
BOT_TOKEN=YOUR_DEVELOPMENT_BOT_TOKEN BOT_TOKEN=YOUR_DEVELOPMENT_BOT_TOKEN
APPLICATION_ID=YOUR_DEVELOPMENT_APPLICATION_ID

View File

@ -1,3 +1,4 @@
NODE_ENV=production NODE_ENV=production
LOG_LEVEL=error LOG_LEVEL=error
BOT_TOKEN=YOUR_PRODUCTION_BOT_TOKEN BOT_TOKEN=YOUR_PRODUCTION_BOT_TOKEN
APPLICATION_ID=YOUR_PRODUCTION_APPLICATION_ID

67
package-lock.json generated
View File

@ -9,7 +9,9 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"discord.js": "^14.16.3" "@discordjs/voice": "^0.17.0",
"discord.js": "^14.16.3",
"dotenv": "^16.4.5"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.1.7" "nodemon": "^3.1.7"
@ -125,6 +127,31 @@
"url": "https://github.com/discordjs/discord.js?sponsor" "url": "https://github.com/discordjs/discord.js?sponsor"
} }
}, },
"node_modules/@discordjs/voice": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.17.0.tgz",
"integrity": "sha512-hArn9FF5ZYi1IkxdJEVnJi+OxlwLV0NJYWpKXsmNOojtGtAZHxmsELA+MZlu2KW1F/K1/nt7lFOfcMXNYweq9w==",
"license": "Apache-2.0",
"dependencies": {
"@types/ws": "^8.5.10",
"discord-api-types": "0.37.83",
"prism-media": "^1.3.5",
"tslib": "^2.6.2",
"ws": "^8.16.0"
},
"engines": {
"node": ">=16.11.0"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/voice/node_modules/discord-api-types": {
"version": "0.37.83",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.83.tgz",
"integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==",
"license": "MIT"
},
"node_modules/@discordjs/ws": { "node_modules/@discordjs/ws": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.1.1.tgz",
@ -367,6 +394,18 @@
"url": "https://github.com/discordjs/discord.js?sponsor" "url": "https://github.com/discordjs/discord.js?sponsor"
} }
}, },
"node_modules/dotenv": {
"version": "16.4.5",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/fast-deep-equal": { "node_modules/fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -567,6 +606,32 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/prism-media": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.5.tgz",
"integrity": "sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==",
"license": "Apache-2.0",
"peerDependencies": {
"@discordjs/opus": ">=0.8.0 <1.0.0",
"ffmpeg-static": "^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0",
"node-opus": "^0.3.3",
"opusscript": "^0.0.8"
},
"peerDependenciesMeta": {
"@discordjs/opus": {
"optional": true
},
"ffmpeg-static": {
"optional": true
},
"node-opus": {
"optional": true
},
"opusscript": {
"optional": true
}
}
},
"node_modules/pstree.remy": { "node_modules/pstree.remy": {
"version": "1.1.8", "version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",

View File

@ -11,7 +11,9 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"discord.js": "^14.16.3" "@discordjs/voice": "^0.17.0",
"discord.js": "^14.16.3",
"dotenv": "^16.4.5"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.1.7" "nodemon": "^3.1.7"

View File

@ -0,0 +1,17 @@
const { SlashCommandBuilder } = require('discord.js');
const { getVoiceConnection } = require('@discordjs/voice');
module.exports = {
data: new SlashCommandBuilder()
.setName('disconnect')
.setDescription('Disconnect from the voice channel'),
async execute(interaction) {
const connection = getVoiceConnection(interaction.guild.id);
if (connection) {
connection.destroy();
await interaction.reply('ボイスチャンネルから切断しました。');
} else {
await interaction.reply('ボイスチャンネルに接続していません。');
}
},
};

23
src/commands/join.js Normal file
View File

@ -0,0 +1,23 @@
const { SlashCommandBuilder } = require('discord.js');
const { joinVoiceChannel } = require('@discordjs/voice');
module.exports = {
data: new SlashCommandBuilder()
.setName('join')
.setDescription('Join the voice channel you are in'),
async execute(interaction) {
const voiceChannel = interaction.member.voice.channel;
if (!voiceChannel) {
return interaction.reply('ボイスチャンネルに接続されていません。');
}
joinVoiceChannel({
channelId: voiceChannel.id,
guildId: voiceChannel.guild.id,
adapterCreator: voiceChannel.guild.voiceAdapterCreator,
});
await interaction.reply('ボイスチャンネルに接続しました。');
},
};

View File

@ -0,0 +1,11 @@
module.exports = {
name: 'messageCreate',
execute(message) {
if (message.author.bot) return;
if (message.mentions.has(message.client.user)) {
const response = message.content.replace(`<@${message.client.user.id}>`, '').trim();
message.channel.send(response || "メッセージを受け取りました!");
}
},
};

7
src/events/ready.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
name: 'ready',
once: true,
execute(client) {
console.log(`Logged in as ${client.user.tag}!`);
},
};

View File

@ -1,22 +1,73 @@
const { Client, GatewayIntentBits } = require('discord.js'); require('dotenv').config();
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] }); const { Client, GatewayIntentBits, Collection, REST, Routes } = require('discord.js');
const fs = require('fs');
const path = require('path');
// ボットが起動したときのメッセージ const client = new Client({
client.once('ready', () => { intents: [
console.log(`Logged in as ${client.user.tag}!`); GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildVoiceStates
]
}); });
// メッセージが送信されたときに呼び出されるイベント // コマンドの読み込み
client.on('messageCreate', message => { client.commands = new Collection();
// 自分のメッセージやBotからのメッセージには反応しない const commands = [];
if (message.author.bot) return; const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
// ボットがメンションされた場合に反応 for (const file of commandFiles) {
if (message.mentions.has(client.user)) { const filePath = path.join(commandsPath, file);
const response = message.content.replace(`<@${client.user.id}>`, '').trim(); const command = require(filePath);
client.commands.set(command.data.name, command);
commands.push(command.data.toJSON());
}
message.channel.send(response || "メッセージを受け取りました!"); const rest = new REST({ version: '10' }).setToken(process.env.BOT_TOKEN);
// スラッシュコマンドのグローバル登録
(async () => {
try {
console.log('Registering global slash commands...');
await rest.put(
Routes.applicationCommands(process.env.APPLICATION_ID),
{ body: commands },
);
console.log('Global slash commands registered successfully.');
} catch (error) {
console.error('Error registering global slash commands:', error);
}
})();
// インタラクションの処理
client.on('interactionCreate', async (interaction) => {
if (!interaction.isCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) return;
try {
await command.execute(interaction);
} catch (error) {
console.error(error);
await interaction.reply({ content: 'コマンド実行中にエラーが発生しました。', ephemeral: true });
} }
}); });
// イベントの読み込み
const eventsPath = path.join(__dirname, 'events');
const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js'));
for (const file of eventFiles) {
const filePath = path.join(eventsPath, file);
const event = require(filePath);
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.BOT_TOKEN); client.login(process.env.BOT_TOKEN);