diff --git a/bot.log b/bot.log index 98560cb..d1cf138 100644 --- a/bot.log +++ b/bot.log @@ -4,3 +4,41 @@ 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. (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 + 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 diff --git a/data/config.json b/data/config.json index b08d715..8cc4ac0 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:27", + "alarm_time": "23:35", "last_voice_channel": null } \ No newline at end of file diff --git a/index.js b/index.js index cc68599..cd619da 100644 --- a/index.js +++ b/index.js @@ -1,206 +1,96 @@ process.env.FFMPEG_PATH = require('ffmpeg-static'); -console.log('Bot starting...'); - const { Client, GatewayIntentBits, SlashCommandBuilder, Routes } = require('discord.js'); -const { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus, VoiceConnectionStatus, entersState } = require('@discordjs/voice'); +const { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus } = require('@discordjs/voice'); const { REST } = require('@discordjs/rest'); const fs = require('fs'); const path = require('path'); +// Load Discord Token const configPath = path.join(__dirname, 'data/config.json'); - -function loadConfig() { - if (fs.existsSync(configPath)) { - return JSON.parse(fs.readFileSync(configPath, 'utf8')); - } - return {}; -} - -const config = loadConfig(); +const config = fs.existsSync(configPath) ? JSON.parse(fs.readFileSync(configPath, 'utf8')) : {}; const token = config.discord_token; if (!token) { - console.error('No Discord Token found in data/config.json'); + console.error('ERROR: discord_token not found in data/config.json'); process.exit(1); } const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildVoiceStates, - ] + 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 playing. Bot will stay in the channel.'); + console.log('Audio finished. Bot is staying in the channel (Stay 24/7).'); }); -player.on('error', error => { - console.error('Audio Player Error:', error.message); -}); +player.on('error', error => console.error('Audio Player Error:', error)); -client.on('ready', async () => { - console.log(`Logged in as ${client.user.tag}`); - - // Register commands +async function deployCommands(clientId) { const commands = [ - new SlashCommandBuilder() - .setName('testsahur') - .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()); + new SlashCommandBuilder().setName('join').setDescription('Bot masuk ke Voice Channel user'), + new SlashCommandBuilder().setName('testsahur').setDescription('Memutar file sahur secara instan') + ].map(cmd => cmd.toJSON()); const rest = new REST({ version: '10' }).setToken(token); try { - console.log('Started refreshing application (/) commands.'); - await rest.put(Routes.applicationCommands(client.user.id), { body: commands }); - console.log('Successfully reloaded application (/) commands.'); - } catch (error) { - console.error('Error reloading commands:', error); + await rest.put(Routes.applicationCommands(clientId), { body: commands }); + console.log('Slash commands deployed successfully.'); + } catch (err) { + console.error('Failed to deploy commands:', err); } - - // Auto-reconnect to last voice channel - const currentConfig = loadConfig(); - const lastVoice = currentConfig.last_voice_channel; - if (lastVoice && lastVoice.guildId && lastVoice.channelId) { - console.log(`Auto-rejoining channel ${lastVoice.channelId}`); - joinVC(lastVoice.guildId, lastVoice.channelId); - } -}); - -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({ - channelId: cId, - guildId: gId, - adapterCreator: guild.voiceAdapterCreator, - selfDeaf: false, - selfMute: false, - }); - - connection.on(VoiceConnectionStatus.Disconnected, async () => { - try { - await Promise.race([ - entersState(connection, VoiceConnectionStatus.Signalling, 5_000), - entersState(connection, VoiceConnectionStatus.Connecting, 5_000), - ]); - } catch (error) { - console.log('Connection lost, attempting to reconnect...'); - setTimeout(() => joinVC(gId, cId), 5000); - } - }); - - connection.on('error', error => { - console.error('Voice Connection Error:', error); - }); - - connection.subscribe(player); } +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(); + + const { commandName, member } = interaction; + + if (!member.voice.channel) { + return interaction.editReply('Silakan masuk ke Voice Channel terlebih dahulu!'); + } + try { - if (interaction.commandName === 'testsahur') { - const member = interaction.member; - if (!member.voice.channel) { - return interaction.reply('Kamu harus berada di Voice Channel!'); - } + const connection = joinVoiceChannel({ + channelId: member.voice.channel.id, + guildId: interaction.guildId, + adapterCreator: interaction.guild.voiceAdapterCreator, + selfDeaf: false, + selfMute: false, + }); - const channel = member.voice.channel; - const gId = interaction.guildId; - const cId = channel.id; + connection.subscribe(player); - // 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); + 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.reply(`File audio tidak ditemukan: ${audioPath}`); + return interaction.editReply('File ./assets/audio/sahur.mp3 tidak ditemukan!'); } const resource = createAudioResource(audioPath, { inlineVolume: true }); - resource.volume.setVolume(1.0); + resource.volume.setVolume(1.0); // Max Volume 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.'); + return interaction.editReply('Memutar suara sahur... 🔊'); } } 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 }); - } + console.error('Error during interaction:', error); + return interaction.editReply('Terjadi kesalahan teknis.'); } }); -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, { inlineVolume: true }); - resource.volume.setVolume(1.0); - player.play(resource); - } - } catch (e) { - console.error('Failed to trigger alarm VC:', e); - } - } - } - } -}, 30000); // Check every 30 seconds - client.login(token);