38530-vm/index.js
2026-02-18 02:23:46 +00:00

207 lines
7.9 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 { GoogleGenerativeAI } = require('@google/generative-ai');
const express = require('express');
require('dotenv').config();
// 1. Keep-Alive Server (Port 8080)
const app = express();
app.get('/', (req, res) => res.send('Wizzy Bot is Online!'));
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => console.log(`✅ Server Keep-Alive aktif di port ${PORT}`));
// 2. Gemini AI Setup
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash' });
// 3. Discord Client Setup
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
});
// 4. DisTube Setup (Music)
const distube = new DisTube(client, {
emitNewSongOnly: true,
emitAddSongWhenCreatingQueue: false,
emitAddListWhenCreatingQueue: false,
plugins: [
new YouTubePlugin(),
new YtDlpPlugin()
]
});
// 5. Slash Commands Definition
const commands = [
new SlashCommandBuilder()
.setName('wizzy')
.setDescription('Tanya Wizzy (Gemini AI)')
.addStringOption(option =>
option.setName('prompt')
.setDescription('Pertanyaanmu untuk Wizzy')
.setRequired(true)),
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());
// 6. Interaction Handling (Slash Commands)
client.on('interactionCreate', async interaction => {
// ⚡ INSTANT DEFER: Prevent 3s Timeout
if (interaction.isChatInputCommand()) {
await interaction.deferReply().catch(e => console.error('Defer Error:', e));
}
if (!interaction.isChatInputCommand()) return;
console.log(`--- Perintah masuk: /${interaction.commandName} ---`);
const { commandName } = interaction;
// --- WIZZY (GEMINI AI) HANDLER ---
if (commandName === 'wizzy') {
try {
const userInput = interaction.options.getString('prompt') ?? 'Halo!';
const result = await model.generateContent(userInput);
const response = result.response.text();
const reply = response.length > 1990 ? response.substring(0, 1990) + '...' : response;
await interaction.editReply(reply);
} catch (error) {
console.error('❌ Gemini Error:', error);
await interaction.editReply({ content: '⚠️ Wizzy mengalami error, coba lagi nanti.', ephemeral: true });
}
return;
}
// --- MUSIC HANDLERS ---
if (commandName === 'play') {
try {
const query = interaction.options.getString('query');
if (!interaction.member.voice.channel) {
return interaction.editReply('Kamu harus berada di voice channel!');
}
await interaction.editReply({ content: `🔍 Mencari: **${query}**...` });
await distube.play(interaction.member.voice.channel, query, {
textChannel: interaction.channel,
member: interaction.member,
interaction
});
} catch (error) {
console.error('Play Error:', error);
await interaction.editReply({ content: `❌ Error: ${error.message}` });
}
} else if (commandName === 'skip') {
try {
const queue = distube.getQueue(interaction.guild);
if (!queue) return interaction.editReply('❌ Tidak ada lagu!');
await distube.skip(interaction.guild);
await interaction.editReply('⏭️ Lagu dilewati!');
} catch (e) { await interaction.editReply(`❌ Error: ${e.message}`); }
} else if (commandName === 'stop') {
try {
await distube.stop(interaction.guild);
await interaction.editReply('⏹️ Musik berhenti!');
} catch (e) { await interaction.editReply(`❌ Error: ${e.message}`); }
} else if (commandName === 'pause') {
try {
distube.pause(interaction.guild);
await interaction.editReply('⏸️ Musik dijeda!');
} catch (e) { await interaction.editReply(`❌ Error: ${e.message}`); }
} else if (commandName === 'resume') {
try {
distube.resume(interaction.guild);
await interaction.editReply('▶️ Musik lanjut!');
} catch (e) { await interaction.editReply(`❌ Error: ${e.message}`); }
} else if (commandName === 'queue') {
try {
const queue = distube.getQueue(interaction.guild);
if (!queue) return interaction.editReply('📭 Antrean kosong!');
const q = queue.songs.map((song, i) => `${i === 0 ? '▶️' : `${i}.`} ${song.name}`).join('\n');
await interaction.editReply(`🎶 **Antrean:**\n${q.slice(0, 1900)}`);
} catch (e) { await interaction.editReply(`❌ Error: ${e.message}`); }
}
});
// 7. Message Handling (Prefix Command !wizzy)
client.on('messageCreate', async (message) => {
if (message.author.bot) return;
if (!message.content.startsWith('!wizzy ')) return;
const userInput = message.content.slice(7).trim();
if (!userInput) return message.reply('Tulis pertanyaanmu!');
await message.channel.sendTyping();
try {
const result = await model.generateContent(userInput);
const response = result.response.text();
const reply = response.length > 1990 ? response.substring(0, 1990) + '...' : response;
await message.reply(reply);
} catch (error) {
console.error('❌ Error Gemini (Prefix):', error);
await message.reply('⚠️ Terjadi error pada Wizzy!');
}
});
// 8. DisTube Events
distube
.on('playSong', (queue, song) => {
queue.textChannel.send(`🎶 Memutar: **${song.name}** (\`${song.formattedDuration}\`)`);
})
.on('addSong', (queue, song) => {
queue.textChannel.send(`✅ Ditambahkan: **${song.name}**`);
})
.on('error', (channel, e) => {
if (channel?.send) channel.send(`❌ DisTube Error: ${e.message.slice(0, 1000)}`);
console.error('DisTube Error:', e);
});
// 9. Ready Event & Command Registration
client.once('ready', async () => {
console.log(`✅ Wizzy aktif sebagai ${client.user.tag}`);
console.log('Bot siap memproses perintah!');
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
try {
console.log('Registering slash commands...');
await rest.put(
Routes.applicationCommands(client.user.id),
{ body: commands },
);
console.log('Successfully registered slash commands!');
} catch (error) {
console.error('Registration Error:', error);
}
});
// 10. Anti-Crash
process.on('unhandledRejection', e => console.error('Unhandled Rejection:', e));
process.on('uncaughtException', e => console.error('Uncaught Exception:', e));
// 11. Login
console.log('Logging in...');
client.login(process.env.DISCORD_TOKEN);