diff --git a/bot.log b/bot.log index d1cf138..950b93a 100644 --- a/bot.log +++ b/bot.log @@ -1,44 +1,19 @@ -Bot starting... -Logged in as AsepXiaoQin#6954 -Started refreshing application (/) commands. -(node:8584) 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. +Bot logged in as AsepXiaoQin#6954 +(node:11761) 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. (Use `node --trace-deprecation ...` to show where the warning was created) -Successfully reloaded application (/) commands. -Interaction Error: Error: Error: Cannot find module '@discordjs/opus' -Require stack: -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/util/loader.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/Opus.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/index.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/index.js -- /home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js -- /home/ubuntu/executor/workspace/index.js -Error: Cannot find module 'node-opus' -Require stack: -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/util/loader.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/Opus.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/index.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/index.js -- /home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js -- /home/ubuntu/executor/workspace/index.js -Error: Cannot find module 'opusscript' -Require stack: -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/util/loader.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/Opus.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/index.js -- /home/ubuntu/executor/workspace/node_modules/prism-media/src/index.js -- /home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js -- /home/ubuntu/executor/workspace/index.js - at Object.loader [as require] (/home/ubuntu/executor/workspace/node_modules/prism-media/src/util/loader.js:12:9) - at loadOpus (/home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/Opus.js:17:17) - at new OpusStream (/home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/Opus.js:46:10) - at new Encoder (/home/ubuntu/executor/workspace/node_modules/prism-media/src/opus/Opus.js:149:5) - at Object.transformer (/home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js:2224:24) - at /home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js:2457:58 - at Array.map () - at createAudioResource (/home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js:2457:39) - at Client. (/home/ubuntu/executor/workspace/index.js:138:30) - at Client.emit (node:events:518:28) -(node:8584) Warning: Supplying "ephemeral" for interaction response options is deprecated. Utilize flags instead. -Voice Connection Error: Error: No compatible encryption modes. Available include: aead_aes256_gcm_rtpsize, aead_xchacha20_poly1305_rtpsize +Slash commands registered. +Command dijalankan... /testsahur +Command dijalankan... /join +/home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js:529 + throw new Error(`No compatible encryption modes. Available include: ${options.join(", ")}`); + ^ + +Error: No compatible encryption modes. Available include: aead_aes256_gcm_rtpsize, aead_xchacha20_poly1305_rtpsize at chooseEncryptionMode (/home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js:529:11) at /home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js:721:21 +Emitted 'error' event on VoiceConnection instance at: + at VoiceConnection.onNetworkingError (/home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js:1914:10) + at Networking.emit (node:events:518:28) + at /home/ubuntu/executor/workspace/node_modules/@discordjs/voice/dist/index.js:729:32 + +Node.js v22.18.0 diff --git a/data/config.json b/data/config.json index 8cc4ac0..70dac7d 100644 --- a/data/config.json +++ b/data/config.json @@ -2,6 +2,6 @@ "discord_token": "MTQ3MTkwOTE5Mzg4Njg1OTI5NA.GCEdpc.jMIxPFsquVAhp88x3dO-yWUFI7e1u1r8oIZTcw", "guild_id": "1428530728706117632", "voice_channel_id": "1457687430189682781", - "alarm_time": "23:35", + "alarm_time": "05:46", "last_voice_channel": null } \ No newline at end of file diff --git a/index.js b/index.js index cd619da..ee83d88 100644 --- a/index.js +++ b/index.js @@ -1,95 +1,88 @@ process.env.FFMPEG_PATH = require('ffmpeg-static'); const { Client, GatewayIntentBits, SlashCommandBuilder, Routes } = require('discord.js'); -const { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus } = require('@discordjs/voice'); +const { joinVoiceChannel, createAudioPlayer, createAudioResource, getVoiceConnection, VoiceConnectionStatus } = require('@discordjs/voice'); const { REST } = require('@discordjs/rest'); +const { join } = require('path'); const fs = require('fs'); -const path = require('path'); -// Load Discord Token -const configPath = path.join(__dirname, 'data/config.json'); -const config = fs.existsSync(configPath) ? JSON.parse(fs.readFileSync(configPath, 'utf8')) : {}; +// Load Config +const config = JSON.parse(fs.readFileSync(join(__dirname, 'data/config.json'), 'utf8')); const token = config.discord_token; -if (!token) { - console.error('ERROR: discord_token not found in data/config.json'); - process.exit(1); -} - const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates] }); const player = createAudioPlayer(); -// Stay 24/7 Logic: Do nothing when idle (prevents automatic leave) -player.on(AudioPlayerStatus.Idle, () => { - console.log('Audio finished. Bot is staying in the channel (Stay 24/7).'); -}); - -player.on('error', error => console.error('Audio Player Error:', error)); - -async function deployCommands(clientId) { +client.on('ready', async () => { + console.log(`Bot logged in as ${client.user.tag}`); + + // Register Commands const commands = [ - new SlashCommandBuilder().setName('join').setDescription('Bot masuk ke Voice Channel user'), - new SlashCommandBuilder().setName('testsahur').setDescription('Memutar file sahur secara instan') + new SlashCommandBuilder().setName('join').setDescription('Bot masuk ke Voice Channel'), + new SlashCommandBuilder().setName('testsahur').setDescription('Test audio sahur') ].map(cmd => cmd.toJSON()); const rest = new REST({ version: '10' }).setToken(token); try { - await rest.put(Routes.applicationCommands(clientId), { body: commands }); - console.log('Slash commands deployed successfully.'); + await rest.put(Routes.applicationCommands(client.user.id), { body: commands }); + console.log('Slash commands registered.'); } catch (err) { - console.error('Failed to deploy commands:', err); + console.error('Failed to register commands:', err); } -} - -client.on('ready', async () => { - console.log(`Bot logged in as ${client.user.tag}`); - await deployCommands(client.user.id); }); client.on('interactionCreate', async interaction => { if (!interaction.isChatInputCommand()) return; - // Anti-Timeout logic - if (!interaction.deferred) await interaction.deferReply(); + if (interaction.commandName === 'join') { + await interaction.deferReply(); // Baris PERTAMA + console.log('Command dijalankan... /join'); - const { commandName, member } = interaction; + const channel = interaction.member.voice.channel; + if (!channel) return interaction.editReply('Masuk ke Voice Channel dulu!'); - if (!member.voice.channel) { - return interaction.editReply('Silakan masuk ke Voice Channel terlebih dahulu!'); + // Clean Connection Logic: Cek koneksi yang sudah ada + let connection = getVoiceConnection(interaction.guildId); + if (!connection) { + connection = joinVoiceChannel({ + channelId: channel.id, + guildId: interaction.guildId, + adapterCreator: interaction.guild.voiceAdapterCreator, + selfDeaf: false + }); + + // Stay 24/7: Pastikan bot tidak disconnect + connection.on(VoiceConnectionStatus.Disconnected, () => { + console.log('Bot terputus dari voice channel.'); + }); + + await interaction.editReply('Berhasil join ke Voice Channel dan Standby 24/7!'); + } else { + await interaction.editReply('Bot sudah berada di dalam Voice Channel.'); + } } - try { - const connection = joinVoiceChannel({ - channelId: member.voice.channel.id, - guildId: interaction.guildId, - adapterCreator: interaction.guild.voiceAdapterCreator, - selfDeaf: false, - selfMute: false, - }); + if (interaction.commandName === 'testsahur') { + await interaction.deferReply(); // Baris PERTAMA + console.log('Command dijalankan... /testsahur'); - connection.subscribe(player); + const connection = getVoiceConnection(interaction.guildId); + if (!connection) return interaction.editReply('Bot belum join! Gunakan /join dulu.'); - if (commandName === 'join') { - return interaction.editReply('Sudah join! 🎵'); - } - - if (commandName === 'testsahur') { - const audioPath = path.join(__dirname, 'assets/audio/sahur.mp3'); - if (!fs.existsSync(audioPath)) { - return interaction.editReply('File ./assets/audio/sahur.mp3 tidak ditemukan!'); - } - - const resource = createAudioResource(audioPath, { inlineVolume: true }); - resource.volume.setVolume(1.0); // Max Volume + try { + // Audio Fix as requested + const resource = createAudioResource(join(__dirname, 'assets/audio/sahur.mp3')); player.play(resource); + connection.subscribe(player); - return interaction.editReply('Memutar suara sahur... 🔊'); + // Edit Reply as requested + await interaction.editReply('Memutar audio sahur... 🔊'); + } catch (error) { + console.error('Error playing audio:', error); + await interaction.editReply('Gagal memutar audio. Pastikan file sahur.mp3 ada di folder assets/audio/'); } - } catch (error) { - console.error('Error during interaction:', error); - return interaction.editReply('Terjadi kesalahan teknis.'); } }); diff --git a/package-lock.json b/package-lock.json index 4a06141..e6c59a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "@discordjs/voice": "^0.17.0", "discord.js": "^14.15.3", "ffmpeg-static": "^5.2.0", - "libsodium-wrappers": "^0.7.13" + "libsodium-wrappers": "^0.7.16", + "opusscript": "^0.0.8" } }, "node_modules/@derhuerst/http-basic": { @@ -487,6 +488,12 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/opusscript": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/opusscript/-/opusscript-0.0.8.tgz", + "integrity": "sha512-VSTi1aWFuCkRCVq+tx/BQ5q9fMnQ9pVZ3JU4UHKqTkf0ED3fKEPdr+gKAAl3IA2hj9rrP6iyq3hlcJq3HELtNQ==", + "license": "MIT" + }, "node_modules/parse-cache-control": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", diff --git a/package.json b/package.json index bc42677..4ea91d3 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,10 @@ "description": "Discord Alarm Sahur Bot", "main": "index.js", "dependencies": { - "discord.js": "^14.15.3", "@discordjs/voice": "^0.17.0", + "discord.js": "^14.15.3", "ffmpeg-static": "^5.2.0", - "libsodium-wrappers": "^0.7.13" + "libsodium-wrappers": "^0.7.16", + "opusscript": "^0.0.8" } }