const { Client, GatewayIntentBits, SlashCommandBuilder, Routes } = require('discord.js'); const { joinVoiceChannel, createAudioPlayer, createAudioResource, StreamType, getVoiceConnection } = require('@discordjs/voice'); const fs = require('fs'); const path = require('path'); const { REST } = require('@discordjs/rest'); // Load Config const config = JSON.parse(fs.readFileSync('./data/config.json', 'utf8')); const token = config.discord_token; const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates] }); const player = createAudioPlayer(); player.on('error', err => { console.log('LOG ERROR AUDIO:', err.message); }); player.on('stateChange', (old, current) => { console.log('Status Audio Saat Ini:', current.status); }); client.on('ready', async () => { console.log(`Bot Minimalis Ready: ${client.user.tag}`); const commands = [ new SlashCommandBuilder().setName('join').setDescription('Bot join ke Voice Channel'), new SlashCommandBuilder().setName('testsahur').setDescription('Tes putar sahur.mp3') ].map(cmd => cmd.toJSON()); const rest = new REST({ version: '10' }).setToken(token); try { await rest.put(Routes.applicationCommands(client.user.id), { body: commands }); console.log('Slash Commands registered.'); } catch (error) { console.error('Error registering commands:', error); } }); client.on('interactionCreate', async interaction => { if (!interaction.isChatInputCommand()) return; // Fix untuk /join if (interaction.commandName === 'join') { // Gunakan Defer Reply di awal await interaction.deferReply(); try { const channel = interaction.member.voice.channel; if (!channel) return interaction.editReply('Masuk ke VC dulu!'); joinVoiceChannel({ channelId: channel.id, guildId: interaction.guildId, adapterCreator: interaction.guild.voiceAdapterCreator, selfDeaf: false, selfMute: false }); await interaction.editReply('Berhasil join ke Voice Channel!'); } catch (error) { // Anti-Stuck: Tangkap error agar tidak diam saja await interaction.editReply('Error: ' + error.message); } } // Fix untuk /testsahur if (interaction.commandName === 'testsahur') { // Gunakan Defer Reply di awal await interaction.deferReply(); try { const channel = interaction.member.voice.channel; if (!channel) return interaction.editReply('Masuk ke VC dulu!'); const connection = joinVoiceChannel({ channelId: channel.id, guildId: interaction.guildId, adapterCreator: interaction.guild.voiceAdapterCreator, selfDeaf: false, selfMute: false }); // Direct Path const filePath = './assets/audio/sahur.mp3'; // Verify File if (!fs.existsSync(filePath)) { return interaction.editReply('Error: File tidak ditemukan di assets/audio!'); } // Hapus Stream Kompleks & Gunakan Jalur Langsung const resource = createAudioResource('./assets/audio/sahur.mp3', { inputType: StreamType.Arbitrary, inlineVolume: true }); // Debug Status console.log('Resource Readable:', resource.readable); console.log('Connection Status:', connection.state.status); // Kabel Utama (Subscribe) const subscription = connection.subscribe(player); player.play(resource); await interaction.editReply('🔊 Sedang memutar sahur.mp3...'); } catch (error) { // Anti-Stuck: Tangkap error agar tidak diam saja await interaction.editReply('Error: ' + error.message); } } // Interaction Timeout Fix: Jika belum dibalas atau di-defer if (!interaction.replied && !interaction.deferred) { try { await interaction.reply('Sedang diproses...'); } catch (err) { console.error('Fallback reply failed:', err.message); } } }); client.login(token);