V2
This commit is contained in:
parent
91498377d0
commit
2c48546b22
67
bot.log
67
bot.log
@ -1,4 +1,63 @@
|
|||||||
Logged in as AsepXiaoQin#6954
|
Interaction Error: DiscordAPIError[10062]: Unknown interaction
|
||||||
(node:4352) DeprecationWarning: The ready event has been renamed to clientReady to distinguish it from the gateway READY event and will only emit under that name in v15. Please use clientReady instead.
|
at handleErrors (/home/ubuntu/executor/workspace/node_modules/@discordjs/rest/dist/index.js:762:13)
|
||||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
|
||||||
Successfully registered application commands.
|
at async BurstHandler.runRequest (/home/ubuntu/executor/workspace/node_modules/@discordjs/rest/dist/index.js:866:23)
|
||||||
|
at async _REST.request (/home/ubuntu/executor/workspace/node_modules/@discordjs/rest/dist/index.js:1307:22)
|
||||||
|
at async ChatInputCommandInteraction.reply (/home/ubuntu/executor/workspace/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js:193:22)
|
||||||
|
at async Client.<anonymous> (/home/ubuntu/executor/workspace/index.js:68:13) {
|
||||||
|
requestBody: { files: [], json: { type: 4, data: [Object] } },
|
||||||
|
rawError: { message: 'Unknown interaction', code: 10062 },
|
||||||
|
code: 10062,
|
||||||
|
status: 404,
|
||||||
|
method: 'POST',
|
||||||
|
url: 'https://discord.com/api/v10/interactions/1472990887029248135/aW50ZXJhY3Rpb246MTQ3Mjk5MDg4NzAyOTI0ODEzNTp2V1dQTFpXN3IybjBtYmZNcjJxaW5qZnlBR1RQdVpKelhnYjdiRUtWQmI1YW9IbXpZS25WVzQzVVpEWVpSa2hVY3FlamhRYVdlaEt0dVlYRVI5bUNCMVM3bnNmUjZhbDBqZk1RdEhrYXB5R3p6VWZsbUNwQUl6RURGa3hkWEwzaw/callback?with_response=false'
|
||||||
|
}
|
||||||
|
(node:7629) Warning: Supplying "ephemeral" for interaction response options is deprecated. Utilize flags instead.
|
||||||
|
(Use `node --trace-warnings ...` to show where the warning was created)
|
||||||
|
node:events:496
|
||||||
|
throw er; // Unhandled 'error' event
|
||||||
|
^
|
||||||
|
|
||||||
|
DiscordAPIError[10062]: Unknown interaction
|
||||||
|
at handleErrors (/home/ubuntu/executor/workspace/node_modules/@discordjs/rest/dist/index.js:762:13)
|
||||||
|
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
|
||||||
|
at async BurstHandler.runRequest (/home/ubuntu/executor/workspace/node_modules/@discordjs/rest/dist/index.js:866:23)
|
||||||
|
at async _REST.request (/home/ubuntu/executor/workspace/node_modules/@discordjs/rest/dist/index.js:1307:22)
|
||||||
|
at async ChatInputCommandInteraction.reply (/home/ubuntu/executor/workspace/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js:193:22)
|
||||||
|
at async Client.<anonymous> (/home/ubuntu/executor/workspace/index.js:156:9)
|
||||||
|
Emitted 'error' event on Client instance at:
|
||||||
|
at emitUnhandledRejectionOrErr (node:events:401:10)
|
||||||
|
at process.processTicksAndRejections (node:internal/process/task_queues:92:21) {
|
||||||
|
requestBody: {
|
||||||
|
files: [],
|
||||||
|
json: {
|
||||||
|
type: 4,
|
||||||
|
data: {
|
||||||
|
content: '🔊 Memutar audio Sahur!',
|
||||||
|
tts: false,
|
||||||
|
nonce: undefined,
|
||||||
|
enforce_nonce: false,
|
||||||
|
embeds: undefined,
|
||||||
|
components: undefined,
|
||||||
|
username: undefined,
|
||||||
|
avatar_url: undefined,
|
||||||
|
allowed_mentions: undefined,
|
||||||
|
flags: undefined,
|
||||||
|
message_reference: undefined,
|
||||||
|
attachments: undefined,
|
||||||
|
sticker_ids: undefined,
|
||||||
|
thread_name: undefined,
|
||||||
|
applied_tags: undefined,
|
||||||
|
poll: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rawError: { message: 'Unknown interaction', code: 10062 },
|
||||||
|
code: 10062,
|
||||||
|
status: 404,
|
||||||
|
method: 'POST',
|
||||||
|
url: 'https://discord.com/api/v10/interactions/1472990887029248135/aW50ZXJhY3Rpb246MTQ3Mjk5MDg4NzAyOTI0ODEzNTp2V1dQTFpXN3IybjBtYmZNcjJxaW5qZnlBR1RQdVpKelhnYjdiRUtWQmI1YW9IbXpZS25WVzQzVVpEWVpSa2hVY3FlamhRYVdlaEt0dVlYRVI5bUNCMVM3bnNmUjZhbDBqZk1RdEhrYXB5R3p6VWZsbUNwQUl6RURGa3hkWEwzaw/callback?with_response=false'
|
||||||
|
}
|
||||||
|
|
||||||
|
Node.js v22.18.0
|
||||||
|
ode.js v22.18.0
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
{
|
{
|
||||||
"discord_token": "MTQ3MTkwOTE5Mzg4Njg1OTI5NA.GCEdpc.jMIxPFsquVAhp88x3dO-yWUFI7e1u1r8oIZTcw",
|
"discord_token": "MTQ3MTkwOTE5Mzg4Njg1OTI5NA.GCEdpc.jMIxPFsquVAhp88x3dO-yWUFI7e1u1r8oIZTcw",
|
||||||
"guild_id": "1428530728706117632",
|
"guild_id": "1428530728706117632",
|
||||||
"voice_channel_id": "1457687430189682781",
|
"voice_channel_id": "1457687430189682781",
|
||||||
"last_voice_channel": null
|
"alarm_time": "23:20",
|
||||||
|
"last_voice_channel": {
|
||||||
|
"guildId": "1428530728706117632",
|
||||||
|
"channelId": "1457687430189682781"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
3
db/migrations/003_add_alarm_settings.sql
Normal file
3
db/migrations/003_add_alarm_settings.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- migrations/003_add_alarm_settings.sql
|
||||||
|
INSERT IGNORE INTO bot_settings (setting_key, setting_value) VALUES
|
||||||
|
('alarm_time', '');
|
||||||
140
index.js
140
index.js
@ -1,4 +1,6 @@
|
|||||||
process.env.FFMPEG_PATH = require('ffmpeg-static');
|
process.env.FFMPEG_PATH = require('ffmpeg-static');
|
||||||
|
console.log('Bot starting...');
|
||||||
|
|
||||||
const { Client, GatewayIntentBits, SlashCommandBuilder, Routes } = require('discord.js');
|
const { Client, GatewayIntentBits, SlashCommandBuilder, Routes } = require('discord.js');
|
||||||
const { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus, VoiceConnectionStatus, entersState } = require('@discordjs/voice');
|
const { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus, VoiceConnectionStatus, entersState } = require('@discordjs/voice');
|
||||||
const { REST } = require('@discordjs/rest');
|
const { REST } = require('@discordjs/rest');
|
||||||
@ -16,7 +18,6 @@ function loadConfig() {
|
|||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const token = config.discord_token;
|
const token = config.discord_token;
|
||||||
const guildId = config.guild_id;
|
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
console.error('No Discord Token found in data/config.json');
|
console.error('No Discord Token found in data/config.json');
|
||||||
@ -32,6 +33,10 @@ const client = new Client({
|
|||||||
|
|
||||||
const player = createAudioPlayer();
|
const player = createAudioPlayer();
|
||||||
|
|
||||||
|
player.on('error', error => {
|
||||||
|
console.error('Audio Player Error:', error.message);
|
||||||
|
});
|
||||||
|
|
||||||
client.on('ready', async () => {
|
client.on('ready', async () => {
|
||||||
console.log(`Logged in as ${client.user.tag}`);
|
console.log(`Logged in as ${client.user.tag}`);
|
||||||
|
|
||||||
@ -39,29 +44,44 @@ client.on('ready', async () => {
|
|||||||
const commands = [
|
const commands = [
|
||||||
new SlashCommandBuilder()
|
new SlashCommandBuilder()
|
||||||
.setName('testsahur')
|
.setName('testsahur')
|
||||||
.setDescription('Memutar file audio sahur')
|
.setDescription('Memutar file audio sahur'),
|
||||||
|
new SlashCommandBuilder()
|
||||||
|
.setName('join')
|
||||||
|
.setDescription('Menyuruh bot join ke voice channel kamu'),
|
||||||
|
new SlashCommandBuilder()
|
||||||
|
.setName('stop')
|
||||||
|
.setDescription('Menghentikan pemutaran audio')
|
||||||
].map(command => command.toJSON());
|
].map(command => command.toJSON());
|
||||||
|
|
||||||
const rest = new REST({ version: '10' }).setToken(token);
|
const rest = new REST({ version: '10' }).setToken(token);
|
||||||
try {
|
try {
|
||||||
|
console.log('Started refreshing application (/) commands.');
|
||||||
await rest.put(Routes.applicationCommands(client.user.id), { body: commands });
|
await rest.put(Routes.applicationCommands(client.user.id), { body: commands });
|
||||||
console.log('Successfully registered application commands.');
|
console.log('Successfully reloaded application (/) commands.');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error('Error reloading commands:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-reconnect to last voice channel
|
// Auto-reconnect to last voice channel
|
||||||
const lastVoice = config.last_voice_channel;
|
const currentConfig = loadConfig();
|
||||||
|
const lastVoice = currentConfig.last_voice_channel;
|
||||||
if (lastVoice && lastVoice.guildId && lastVoice.channelId) {
|
if (lastVoice && lastVoice.guildId && lastVoice.channelId) {
|
||||||
|
console.log(`Auto-rejoining channel ${lastVoice.channelId}`);
|
||||||
joinVC(lastVoice.guildId, lastVoice.channelId);
|
joinVC(lastVoice.guildId, lastVoice.channelId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function joinVC(gId, cId) {
|
function joinVC(gId, cId) {
|
||||||
|
const guild = client.guilds.cache.get(gId);
|
||||||
|
if (!guild) {
|
||||||
|
console.error(`Guild ${gId} not found in cache`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const connection = joinVoiceChannel({
|
const connection = joinVoiceChannel({
|
||||||
channelId: cId,
|
channelId: cId,
|
||||||
guildId: gId,
|
guildId: gId,
|
||||||
adapterCreator: client.guilds.cache.get(gId).voiceAdapterCreator,
|
adapterCreator: guild.voiceAdapterCreator,
|
||||||
selfDeaf: false,
|
selfDeaf: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -77,33 +97,103 @@ function joinVC(gId, cId) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connection.on('error', error => {
|
||||||
|
console.error('Voice Connection Error:', error);
|
||||||
|
});
|
||||||
|
|
||||||
connection.subscribe(player);
|
connection.subscribe(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
client.on('interactionCreate', async interaction => {
|
client.on('interactionCreate', async interaction => {
|
||||||
if (!interaction.isChatInputCommand()) return;
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
if (interaction.commandName === 'testsahur') {
|
try {
|
||||||
const member = interaction.member;
|
if (interaction.commandName === 'testsahur') {
|
||||||
if (!member.voice.channel) {
|
const member = interaction.member;
|
||||||
return interaction.reply('Kamu harus berada di Voice Channel!');
|
if (!member.voice.channel) {
|
||||||
|
return interaction.reply('Kamu harus berada di Voice Channel!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = member.voice.channel;
|
||||||
|
const gId = interaction.guildId;
|
||||||
|
const cId = channel.id;
|
||||||
|
|
||||||
|
// Save last channel
|
||||||
|
const currentConfig = loadConfig();
|
||||||
|
currentConfig.last_voice_channel = { guildId: gId, channelId: cId };
|
||||||
|
fs.writeFileSync(configPath, JSON.stringify(currentConfig, null, 2));
|
||||||
|
|
||||||
|
joinVC(gId, cId);
|
||||||
|
|
||||||
|
const audioPath = path.join(__dirname, 'assets/audio/sahur.mp3');
|
||||||
|
if (!fs.existsSync(audioPath)) {
|
||||||
|
return interaction.reply(`File audio tidak ditemukan: ${audioPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const resource = createAudioResource(audioPath);
|
||||||
|
player.play(resource);
|
||||||
|
|
||||||
|
await interaction.reply('🔊 Memutar audio Sahur!');
|
||||||
|
} else if (interaction.commandName === 'join') {
|
||||||
|
const member = interaction.member;
|
||||||
|
if (!member.voice.channel) {
|
||||||
|
return interaction.reply('Kamu harus berada di Voice Channel!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = member.voice.channel;
|
||||||
|
const gId = interaction.guildId;
|
||||||
|
const cId = channel.id;
|
||||||
|
|
||||||
|
// Save last channel
|
||||||
|
const currentConfig = loadConfig();
|
||||||
|
currentConfig.last_voice_channel = { guildId: gId, channelId: cId };
|
||||||
|
fs.writeFileSync(configPath, JSON.stringify(currentConfig, null, 2));
|
||||||
|
|
||||||
|
joinVC(gId, cId);
|
||||||
|
await interaction.reply('✅ Bot telah bergabung ke Voice Channel!');
|
||||||
|
} else if (interaction.commandName === 'stop') {
|
||||||
|
player.stop();
|
||||||
|
await interaction.reply('🛑 Audio dihentikan.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Interaction Error:', error);
|
||||||
|
if (interaction.replied || interaction.deferred) {
|
||||||
|
await interaction.followUp({ content: 'Terjadi kesalahan saat menjalankan command!', ephemeral: true });
|
||||||
|
} else {
|
||||||
|
await interaction.reply({ content: 'Terjadi kesalahan saat menjalankan command!', ephemeral: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const channel = member.voice.channel;
|
|
||||||
const gId = interaction.guildId;
|
|
||||||
const cId = channel.id;
|
|
||||||
|
|
||||||
// Save last channel
|
|
||||||
config.last_voice_channel = { guildId: gId, channelId: cId };
|
|
||||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
||||||
|
|
||||||
joinVC(gId, cId);
|
|
||||||
|
|
||||||
const resource = createAudioResource(path.join(__dirname, 'assets/audio/sahur.mp3'));
|
|
||||||
player.play(resource);
|
|
||||||
|
|
||||||
await interaction.reply('🔊 Memutar audio Sahur!');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let lastAlarmMinute = -1;
|
||||||
|
setInterval(() => {
|
||||||
|
const now = new Date();
|
||||||
|
const currentMinute = now.getMinutes();
|
||||||
|
|
||||||
|
if (currentMinute !== lastAlarmMinute) {
|
||||||
|
lastAlarmMinute = currentMinute;
|
||||||
|
|
||||||
|
const currentTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
|
||||||
|
const currentConfig = loadConfig();
|
||||||
|
|
||||||
|
if (currentConfig.alarm_time === currentTime) {
|
||||||
|
console.log(`Alarm triggered at ${currentTime}`);
|
||||||
|
const lastVoice = currentConfig.last_voice_channel;
|
||||||
|
|
||||||
|
if (lastVoice && lastVoice.guildId && lastVoice.channelId) {
|
||||||
|
try {
|
||||||
|
joinVC(lastVoice.guildId, lastVoice.channelId);
|
||||||
|
const audioPath = path.join(__dirname, 'assets/audio/sahur.mp3');
|
||||||
|
if (fs.existsSync(audioPath)) {
|
||||||
|
const resource = createAudioResource(audioPath);
|
||||||
|
player.play(resource);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to trigger alarm VC:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 30000); // Check every 30 seconds
|
||||||
|
|
||||||
client.login(token);
|
client.login(token);
|
||||||
|
|||||||
@ -17,16 +17,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$token = $_POST['discord_token'] ?? '';
|
$token = $_POST['discord_token'] ?? '';
|
||||||
$guild = $_POST['guild_id'] ?? '';
|
$guild = $_POST['guild_id'] ?? '';
|
||||||
$channel = $_POST['voice_channel_id'] ?? '';
|
$channel = $_POST['voice_channel_id'] ?? '';
|
||||||
|
$alarm = $_POST['alarm_time'] ?? '';
|
||||||
|
|
||||||
save_setting('discord_token', $token);
|
save_setting('discord_token', $token);
|
||||||
save_setting('guild_id', $guild);
|
save_setting('guild_id', $guild);
|
||||||
save_setting('voice_channel_id', $channel);
|
save_setting('voice_channel_id', $channel);
|
||||||
|
save_setting('alarm_time', $alarm);
|
||||||
|
|
||||||
// Also update JSON for the bot
|
// Also update JSON for the bot
|
||||||
$config = [
|
$config = [
|
||||||
'discord_token' => $token,
|
'discord_token' => $token,
|
||||||
'guild_id' => $guild,
|
'guild_id' => $guild,
|
||||||
'voice_channel_id' => $channel,
|
'voice_channel_id' => $channel,
|
||||||
|
'alarm_time' => $alarm,
|
||||||
'last_voice_channel' => json_decode(get_setting('last_voice_channel'), true) ?: null
|
'last_voice_channel' => json_decode(get_setting('last_voice_channel'), true) ?: null
|
||||||
];
|
];
|
||||||
if (!is_dir(__DIR__ . '/data')) mkdir(__DIR__ . '/data', 0775, true);
|
if (!is_dir(__DIR__ . '/data')) mkdir(__DIR__ . '/data', 0775, true);
|
||||||
@ -38,6 +41,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$token = get_setting('discord_token');
|
$token = get_setting('discord_token');
|
||||||
$guildId = get_setting('guild_id');
|
$guildId = get_setting('guild_id');
|
||||||
$voiceId = get_setting('voice_channel_id');
|
$voiceId = get_setting('voice_channel_id');
|
||||||
|
$alarmTime = get_setting('alarm_time');
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -163,6 +167,11 @@ $voiceId = get_setting('voice_channel_id');
|
|||||||
<input type="text" name="voice_channel_id" class="form-control" value="<?= htmlspecialchars($voiceId) ?>" placeholder="9876543210...">
|
<input type="text" name="voice_channel_id" class="form-control" value="<?= htmlspecialchars($voiceId) ?>" placeholder="9876543210...">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label small fw-medium">Alarm Time (HH:MM)</label>
|
||||||
|
<input type="time" name="alarm_time" class="form-control" value="<?= htmlspecialchars($alarmTime) ?>">
|
||||||
|
<div class="hint">Bot will automatically join the voice channel and play audio at this time.</div>
|
||||||
|
</div>
|
||||||
<button type="submit" class="btn btn-primary w-100 mt-2">Save Configuration</button>
|
<button type="submit" class="btn btn-primary w-100 mt-2">Save Configuration</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user