192 lines
7.0 KiB
JavaScript
192 lines
7.0 KiB
JavaScript
process.env.FFMPEG_PATH = require('ffmpeg-static');
|
|
const path = require('path');
|
|
// Tambahkan folder ffmpeg ke PATH agar yt-dlp bisa menemukannya
|
|
const ffmpegDir = path.dirname(process.env.FFMPEG_PATH);
|
|
if (!process.env.PATH.includes(ffmpegDir)) {
|
|
process.env.PATH = `${ffmpegDir}${path.delimiter}${process.env.PATH}`;
|
|
}
|
|
|
|
require('dotenv').config({ path: path.join(__dirname, '.env') });
|
|
const { Client, GatewayIntentBits, Events, EmbedBuilder } = require('discord.js');
|
|
const { DisTube } = require('distube');
|
|
const { YtDlpPlugin } = require('@distube/yt-dlp');
|
|
const { SpotifyPlugin } = require('@distube/spotify');
|
|
const { SoundCloudPlugin } = require('@distube/soundcloud');
|
|
const { CronJob } = require('cron');
|
|
const fs = require('fs');
|
|
|
|
const client = new Client({
|
|
intents: [
|
|
GatewayIntentBits.Guilds,
|
|
GatewayIntentBits.GuildVoiceStates,
|
|
GatewayIntentBits.GuildMessages,
|
|
GatewayIntentBits.MessageContent
|
|
]
|
|
});
|
|
|
|
// Initialize DisTube with the requested plugins
|
|
const distube = new DisTube(client, {
|
|
plugins: [
|
|
new SpotifyPlugin(),
|
|
new SoundCloudPlugin(),
|
|
new YtDlpPlugin() // yt-dlp must be last
|
|
],
|
|
emitNewSongOnly: true,
|
|
emitAddSongWhenCreatingQueue: false,
|
|
emitAddListWhenCreatingQueue: false
|
|
});
|
|
|
|
const VC_ID = process.env.VC_ID;
|
|
const SAHUR_AUDIO_PATH = path.join(__dirname, 'assets/audio/sahur.mp3');
|
|
|
|
function logToFile(message) {
|
|
const logMessage = `[${new Date().toISOString()}] ${message}\n`;
|
|
fs.appendFileSync(path.join(__dirname, 'bot.log'), logMessage);
|
|
console.log(message);
|
|
}
|
|
|
|
// Better Error Handling for DisTube
|
|
distube
|
|
.on('playSong', (queue, song) => {
|
|
logToFile(`Playing: ${song.name}`);
|
|
const embed = new EmbedBuilder()
|
|
.setColor('#00FF00')
|
|
.setTitle('🎶 Sedang Memutar')
|
|
.setDescription(`**${song.name}**`)
|
|
.addFields(
|
|
{ name: 'Durasi', value: song.formattedDuration, inline: true },
|
|
{ name: 'Platform', value: song.source.toUpperCase(), inline: true }
|
|
)
|
|
.setThumbnail(song.thumbnail);
|
|
queue.textChannel.send({ embeds: [embed] });
|
|
})
|
|
.on('addSong', (queue, song) => {
|
|
queue.textChannel.send(`✅ **${song.name}** ditambahkan ke antrean!`);
|
|
})
|
|
.on('error', (channel, e) => {
|
|
const errorMsg = `DisTube Error: ${e.stack || e.message || e}`;
|
|
logToFile(errorMsg);
|
|
if (channel && channel.send) channel.send(`❌ Terjadi kesalahan audio: ${e.message.slice(0, 1000)}`);
|
|
})
|
|
.on('empty', queue => {
|
|
if (queue.textChannel) queue.textChannel.send('Voice channel kosong, bot keluar...');
|
|
})
|
|
.on('searchNoResult', (message, query) => {
|
|
if (message.channel) message.channel.send(`❌ Tidak ada hasil untuk: ${query}`);
|
|
});
|
|
|
|
client.once(Events.ClientReady, async c => {
|
|
logToFile(`Ready! Logged in as ${c.user.tag}`);
|
|
logToFile(`FFMPEG Path: ${process.env.FFMPEG_PATH}`);
|
|
|
|
// Sahur Alarm
|
|
const sahurTime = process.env.SAHUR_TIME || '30 03 * * *';
|
|
let cronTime = sahurTime;
|
|
if (sahurTime.includes(':') && !sahurTime.includes('*')) {
|
|
const [hour, minute] = sahurTime.split(':');
|
|
cronTime = `0 ${minute} ${hour} * * *`;
|
|
}
|
|
|
|
try {
|
|
new CronJob(cronTime, async () => {
|
|
logToFile('Sahur alarm triggered!');
|
|
const guild = client.guilds.cache.first();
|
|
if (!guild) return;
|
|
const channel = guild.channels.cache.get(VC_ID);
|
|
if (channel) {
|
|
distube.play(channel, SAHUR_AUDIO_PATH, {
|
|
skip: true,
|
|
textChannel: guild.systemChannel || guild.channels.cache.find(ch => ch.type === 0)
|
|
});
|
|
}
|
|
}, null, true, 'Asia/Jakarta');
|
|
logToFile(`Alarm scheduled at ${cronTime}`);
|
|
} catch (e) {
|
|
logToFile(`Failed to schedule alarm: ${e.message}`);
|
|
}
|
|
});
|
|
|
|
client.on(Events.InteractionCreate, async interaction => {
|
|
if (!interaction.isChatInputCommand()) return;
|
|
|
|
const { commandName } = interaction;
|
|
const voiceChannel = interaction.member?.voice.channel;
|
|
|
|
if (['play', 'testsahur', 'skip', 'stop', 'pause', 'resume'].includes(commandName) && !voiceChannel) {
|
|
return interaction.reply({ content: 'Kamu harus berada di voice channel!', ephemeral: true });
|
|
}
|
|
|
|
try {
|
|
if (commandName === 'testsahur') {
|
|
await interaction.deferReply();
|
|
logToFile('Executing /testsahur...');
|
|
|
|
if (!fs.existsSync(SAHUR_AUDIO_PATH)) {
|
|
throw new Error(`File tidak ditemukan di: ${SAHUR_AUDIO_PATH}`);
|
|
}
|
|
|
|
await distube.play(voiceChannel, SAHUR_AUDIO_PATH, {
|
|
skip: true,
|
|
member: interaction.member,
|
|
textChannel: interaction.channel
|
|
});
|
|
await interaction.editReply('📢 Memutar suara Sahur untuk pengetesan!');
|
|
}
|
|
|
|
else if (commandName === 'play') {
|
|
const query = interaction.options.getString('query');
|
|
await interaction.deferReply();
|
|
logToFile(`Executing /play with query: ${query}`);
|
|
|
|
if (query.toLowerCase() === 'sahur') {
|
|
await distube.play(voiceChannel, SAHUR_AUDIO_PATH, {
|
|
skip: true,
|
|
member: interaction.member,
|
|
textChannel: interaction.channel
|
|
});
|
|
return interaction.editReply('📢 Memainkan audio Sahur lokal...');
|
|
}
|
|
|
|
await distube.play(voiceChannel, query, {
|
|
textChannel: interaction.channel,
|
|
member: interaction.member
|
|
});
|
|
await interaction.editReply(`🔍 Mencari: **${query}**`);
|
|
}
|
|
|
|
else if (commandName === 'pause') {
|
|
await interaction.deferReply();
|
|
distube.pause(interaction.guildId);
|
|
await interaction.editReply('Musik dipause. ⏸️');
|
|
}
|
|
|
|
else if (commandName === 'resume') {
|
|
await interaction.deferReply();
|
|
distube.resume(interaction.guildId);
|
|
await interaction.editReply('Musik dilanjutkan. ▶️');
|
|
}
|
|
|
|
else if (commandName === 'skip') {
|
|
await interaction.deferReply();
|
|
await distube.skip(interaction.guildId);
|
|
await interaction.editReply('Lagu dilewati! ⏭️');
|
|
}
|
|
|
|
else if (commandName === 'stop') {
|
|
await interaction.deferReply();
|
|
await distube.stop(interaction.guildId);
|
|
await interaction.editReply('Musik dihentikan.');
|
|
}
|
|
|
|
} catch (err) {
|
|
logToFile(`Command Error (${commandName}): ${err.stack || err.message}`);
|
|
if (interaction.deferred || interaction.replied) {
|
|
await interaction.editReply(`❌ Error: ${err.message}`);
|
|
} else {
|
|
await interaction.reply({ content: `❌ Error: ${err.message}`, ephemeral: true });
|
|
}
|
|
}
|
|
});
|
|
|
|
client.login(process.env.DISCORD_TOKEN);
|