diff --git a/api/reset_bot.php b/api/reset_bot.php new file mode 100644 index 0000000..8426041 --- /dev/null +++ b/api/reset_bot.php @@ -0,0 +1,18 @@ + false, 'error' => 'Invalid request method']); + exit; +} + +$output = []; +$return_var = 0; +// Using sudo to run as ubuntu user who owns the pm2 process +exec("sudo -u ubuntu /usr/bin/pm2 restart discord-bot 2>&1", $output, $return_var); + +if ($return_var === 0) { + echo json_encode(['success' => true, 'message' => 'Bot restarted successfully']); +} else { + echo json_encode(['success' => false, 'error' => 'Failed to restart bot', 'details' => implode("\n", $output)]); +} diff --git a/data/config.json b/data/config.json index ac1a192..06eb81f 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": "09:20", + "alarm_time": "15:33", "last_voice_channel": null } \ No newline at end of file diff --git a/index.js b/index.js index d758d97..41883b7 100644 --- a/index.js +++ b/index.js @@ -1,13 +1,15 @@ -const ffmpeg = require('ffmpeg-static'); -process.env.FFMPEG_PATH = ffmpeg; -const { Client, GatewayIntentBits, SlashCommandBuilder, Routes, ActivityType } = require('discord.js'); -const { joinVoiceChannel, createAudioPlayer, createAudioResource, getVoiceConnection, VoiceConnectionStatus, StreamType } = require('@discordjs/voice'); -const { REST } = require('@discordjs/rest'); -const { join } = require('path'); +process.env.FFMPEG_PATH = require('ffmpeg-static'); +require('opusscript'); +require('libsodium-wrappers'); +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(join(__dirname, 'data/config.json'), 'utf8')); +const configPath = path.join(__dirname, 'data/config.json'); +const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); const token = config.discord_token; const client = new Client({ @@ -16,47 +18,89 @@ const client = new Client({ const player = createAudioPlayer(); +// Monitoring Status +player.on('stateChange', (oldState, newState) => { + console.log(`Status Player: ${newState.status}`); +}); + player.on('error', error => { - console.error('Error Audio:', error); + console.log('ERROR AUDIO:', error.message); }); client.on('ready', async () => { - console.log(`Bot logged in as ${client.user.tag}`); + console.log(`Bot Sahur Online: ${client.user.tag}`); - // Set Status Online dan Aktivitas - client.user.setPresence({ - activities: [{ name: 'Lilis', type: ActivityType.Watching }], - status: 'online', - }); - - // Register Commands const commands = [ - new SlashCommandBuilder().setName('join').setDescription('Bot masuk ke Voice Channel'), - new SlashCommandBuilder().setName('testsahur').setDescription('Test audio sahur') + new SlashCommandBuilder().setName('join').setDescription('Perintah untuk bot masuk ke Voice Channel'), + new SlashCommandBuilder().setName('testsahur').setDescription('Perintah untuk memutar suara alarm sahur') ].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.'); + console.log('Slash Commands Berhasil Didaftarkan.'); } catch (err) { - console.error('Failed to register commands:', err); + console.error('Gagal daftar command:', err); } }); client.on('interactionCreate', async interaction => { if (!interaction.isChatInputCommand()) return; + // 1. PERINTAH JOIN (Hanya Masuk) if (interaction.commandName === 'join') { - await interaction.deferReply(); // Baris PERTAMA - console.log('Command dijalankan... /join'); - + await interaction.deferReply(); const channel = interaction.member.voice.channel; - if (!channel) return interaction.editReply('Masuk ke Voice Channel dulu!'); + + if (!channel) { + return interaction.editReply('❌ Kamu harus masuk ke Voice Channel dulu!'); + } - // Clean Connection Logic: Cek koneksi yang sudah ada + const connection = joinVoiceChannel({ + channelId: channel.id, + guildId: interaction.guildId, + adapterCreator: interaction.guild.voiceAdapterCreator, + selfDeaf: false, + selfMute: false, + debug: true + }); + + // Keep-Alive Logic + connection.on('stateChange', (oldState, newState) => { + if (newState.status === 'disconnected') { + console.log('Bot terputus, mencoba masuk kembali...'); + try { + joinVoiceChannel({ + channelId: channel.id, + guildId: interaction.guildId, + adapterCreator: interaction.guild.voiceAdapterCreator, + selfDeaf: false, + selfMute: false + }); + } catch (e) { + console.log('Gagal rejoin:', e.message); + } + } + }); + + console.log('Bot masuk voice!'); + await interaction.editReply('✅ Bot sudah masuk ke Voice Channel. Siap untuk /testsahur!'); + } + + // 2. PERINTAH TESTSAHUR (Auto-Join & Play) + if (interaction.commandName === 'testsahur') { + await interaction.deferReply(); + let connection = getVoiceConnection(interaction.guildId); + const channel = interaction.member.voice.channel; + + // Auto-Reconnect: Jika tidak ada koneksi, join dulu if (!connection) { + if (!channel) { + return interaction.editReply('❌ Bot tidak di VC dan kamu juga tidak di VC. Join VC dulu!'); + } + + console.log('Connection tidak ditemukan, mencoba auto-join...'); connection = joinVoiceChannel({ channelId: channel.id, guildId: interaction.guildId, @@ -64,44 +108,30 @@ client.on('interactionCreate', async interaction => { selfDeaf: false, selfMute: false }); - - // Subscribe player immediately - connection.subscribe(player); - - // 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.'); } - } - - if (interaction.commandName === 'testsahur') { - await interaction.deferReply(); // Baris PERTAMA - console.log('Command dijalankan... /testsahur'); - - const connection = getVoiceConnection(interaction.guildId); - if (!connection) return interaction.editReply('Bot belum join! Gunakan /join dulu.'); try { - // Audio Fix as requested with Volume Booster - const resource = createAudioResource(join(__dirname, 'assets', 'audio', 'sahur.mp3'), { - inputType: StreamType.Arbitrary, + const audioPath = path.join(process.cwd(), 'assets', 'audio', 'sahur.mp3'); + console.log('Membaca file audio di:', audioPath); + + if (!fs.existsSync(audioPath)) { + return interaction.editReply('❌ File audio tidak ditemukan!'); + } + + const resource = createAudioResource(audioPath, { + inputType: StreamType.Arbitrary, inlineVolume: true }); - resource.volume.setVolume(1.0); + resource.volume.setVolume(1.5); connection.subscribe(player); player.play(resource); - - // Edit Reply as requested - await interaction.editReply('Memutar audio sahur... 🔊'); + + console.log('Kabel audio tersambung dan suara diputar!'); + await interaction.editReply('🔊 Sedang memutar alarm sahur (Auto-Connect Aktif)...'); } catch (error) { - console.error('Error playing audio:', error); - await interaction.editReply('Gagal memutar audio. Pastikan file sahur.mp3 ada di folder assets/audio/'); + console.log('ERROR AUDIO:', error.message); + await interaction.editReply('❌ Terjadi kesalahan: ' + error.message); } } }); diff --git a/index.php b/index.php index dbe02c8..30875fd 100644 --- a/index.php +++ b/index.php @@ -127,18 +127,26 @@ $alarmTime = get_setting('alarm_time');
Use these controls to manage the bot process. If the bot is not responding, try resetting it.
+ + +