38530-vm/index.js
2026-02-17 17:34:40 +00:00

139 lines
5.1 KiB
JavaScript

const { Client, GatewayIntentBits, EmbedBuilder, PermissionsBitField, REST, Routes, SlashCommandBuilder } = require('discord.js');
const { DisTube } = require('distube');
const { YtDlpPlugin } = require('@distube/yt-dlp');
const { YouTubePlugin } = require('@distube/youtube');
const express = require('express');
const ffmpeg = require('ffmpeg-static');
require('dotenv').config();
// 1. Keep-Alive System
const app = express();
app.get('/', (req, res) => res.send('Bot Musik Online!'));
app.listen(process.env.PORT || 8080, () => console.log('Keep-Alive aktif di port ' + (process.env.PORT || 8080)));
// 2. Discord Client Setup
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
});
// 3. DisTube Setup
const distube = new DisTube(client, {
emitNewSongOnly: true,
emitAddSongWhenCreatingQueue: false,
emitAddListWhenCreatingQueue: false,
plugins: [
new YouTubePlugin(),
new YtDlpPlugin()
]
});
// 4. Slash Commands Definition
const commands = [
new SlashCommandBuilder()
.setName('play')
.setDescription('Putar musik dari judul atau link')
.addStringOption(option =>
option.setName('query')
.setDescription('Judul lagu atau link (YouTube/Spotify/SoundCloud)')
.setRequired(true)),
new SlashCommandBuilder()
.setName('skip')
.setDescription('Lewati lagu saat ini'),
new SlashCommandBuilder()
.setName('stop')
.setDescription('Berhentikan musik dan keluar dari voice channel'),
new SlashCommandBuilder()
.setName('queue')
.setDescription('Lihat daftar antrean lagu'),
new SlashCommandBuilder()
.setName('pause')
.setDescription('Jeda musik'),
new SlashCommandBuilder()
.setName('resume')
.setDescription('Lanjutkan musik'),
].map(command => command.toJSON());
// 5. Interaction Handling
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
const { commandName } = interaction;
const voiceChannel = interaction.member.voice.channel;
if (!voiceChannel) {
return interaction.reply({ content: 'Kamu harus berada di Voice Channel untuk menggunakan perintah ini!', ephemeral: true });
}
// Anti-Stuck: Defer Reply
await interaction.deferReply();
try {
if (commandName === 'play') {
const query = interaction.options.getString('query');
await distube.play(voiceChannel, query, {
textChannel: interaction.channel,
member: interaction.member
});
await interaction.editReply(`🔍 Sedang mencari dan memutar: **${query}**`);
} else if (commandName === 'skip') {
await distube.skip(interaction.guild);
await interaction.editReply('⏭️ Lagu dilewati!');
} else if (commandName === 'stop') {
await distube.stop(interaction.guild);
await interaction.editReply('⏹️ Musik dihentikan dan bot keluar!');
} else if (commandName === 'pause') {
distube.pause(interaction.guild);
await interaction.editReply('⏸️ Musik dijeda!');
} else if (commandName === 'resume') {
distube.resume(interaction.guild);
await interaction.editReply('▶️ Musik dilanjutkan!');
} else if (commandName === 'queue') {
const queue = distube.getQueue(interaction.guild);
if (!queue) return interaction.editReply('Antrean kosong!');
const q = queue.songs.map((song, i) => `${i === 0 ? 'Memutar:' : `${i}.`} ${song.name} - \`${song.formattedDuration}\``).join('\n');
await interaction.editReply(`🎶 **Antrean Saat Ini:**\n${q.slice(0, 2000)}`);
}
} catch (error) {
console.error(error);
await interaction.editReply(`❌ Terjadi kesalahan: ${error.message}`);
}
});
// 6. DisTube Events
distube
.on('playSong', (queue, song) => {
queue.textChannel.send(`🎶 Sedang memutar: **${song.name}** - \`${song.formattedDuration}\`\nDiminta oleh: ${song.user}`);
})
.on('addSong', (queue, song) => {
queue.textChannel.send(`✅ Menambahkan **${song.name}** ke antrean!`);
})
.on('error', (channel, e) => {
if (channel) channel.send(`❌ Error: ${e.message.slice(0, 1900)}`);
console.error(e);
});
// 7. Client Ready & Command Registration
client.once('ready', async () => {
console.log(`Bot logged in as ${client.user.tag}`);
// Register Global Slash Commands
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
try {
console.log('Memulai refresh slash commands...');
await rest.put(
Routes.applicationCommands(client.user.id),
{ body: commands },
);
console.log('Berhasil mendaftarkan slash commands!');
} catch (error) {
console.error(error);
}
});
client.login(process.env.DISCORD_TOKEN);