|
import config from './config.json' with { type: 'json' }; |
|
import { Client, GatewayIntentBits, Partials } from 'discord.js'; |
|
import { readdirSync } from 'fs'; |
|
import { join } from 'path'; |
|
import type { Command } from './types'; |
|
import { MusicQueue } from './utils/MusicQueue'; |
|
import { SocksProxyAgent } from 'socks-proxy-agent'; |
|
|
|
const commandsDir = join(import.meta.dir, 'Commands'); |
|
const commands: Command[] = readdirSync(commandsDir) |
|
.filter(file => file.endsWith('.ts') || file.endsWith('.js')) |
|
.map(file => { |
|
try { |
|
const commandModule = require(join(commandsDir, file)); |
|
return commandModule.default; |
|
} catch (error) { |
|
console.error(`❌ Failed to load command ${file}:`, error); |
|
return undefined; |
|
} |
|
}) |
|
.filter((cmd): cmd is Command => cmd !== undefined); |
|
|
|
const clients: Client[] = []; |
|
const queues = new Map<string, MusicQueue>(); |
|
|
|
config.tokens.forEach((token: string, index: number) => { |
|
const proxyUrl = 'socks5h://admin1:thanhtai123@74.81.54.129:80'; |
|
const agent = new SocksProxyAgent(proxyUrl); |
|
|
|
const client = new Client({ |
|
intents: [ |
|
GatewayIntentBits.Guilds, |
|
GatewayIntentBits.GuildMessages, |
|
GatewayIntentBits.MessageContent, |
|
GatewayIntentBits.DirectMessages, |
|
GatewayIntentBits.GuildVoiceStates, |
|
], |
|
partials: [Partials.Channel], |
|
http: { |
|
agent: { |
|
https: agent, |
|
}, |
|
}, |
|
}); |
|
|
|
client.once('ready', () => { |
|
console.log(`✅ Client ${index + 1} - ${client.user?.tag} is ready!`); |
|
clients.push(client); |
|
}); |
|
|
|
client.on('messageCreate', async message => { |
|
if (message.author.bot || !message.content.startsWith(config.PREFIX)) return; |
|
|
|
const args = message.content.slice(config.PREFIX.length).trim().split(/\s+/); |
|
const commandName = args.shift()?.toLowerCase(); |
|
const command = commands.find(cmd => cmd?.data?.name === commandName); |
|
|
|
if (!command) { |
|
return message.reply(`❌ Lệnh \`${commandName}\` không tồn tại. Dùng \`${config.PREFIX}help\` để xem danh sách lệnh.`); |
|
} |
|
|
|
if (command.ownersOnly && !config.owners.includes(message.author.id)) { |
|
return message.reply('⛔ Bạn không có quyền dùng lệnh này.'); |
|
} |
|
|
|
try { |
|
await command.execute(message, args, client); |
|
} catch (error) { |
|
console.error(`❌ Lỗi khi xử lý lệnh ${commandName}:`, error); |
|
await message.reply('❌ Có lỗi xảy ra khi chạy lệnh.').catch(console.error); |
|
} |
|
}); |
|
|
|
client.on('voiceStateUpdate', (oldState, newState) => { |
|
const queue = queues.get(oldState.guild.id); |
|
if (!queue || !queue.connection) return; |
|
|
|
const botVoiceChannel = queue.connection.joinConfig.channelId; |
|
if (oldState.channelId === botVoiceChannel && newState.channelId !== botVoiceChannel) { |
|
const channel = oldState.guild.channels.cache.get(botVoiceChannel); |
|
if (channel) { |
|
const members = channel.members.filter(member => !member.user.bot); |
|
if (members.size === 0) { |
|
queue.songs = []; |
|
queue.playing = false; |
|
queue.currentSong = null; |
|
queue.player.stop(); |
|
if (queue.connection) { |
|
queue.connection.destroy(); |
|
queue.connection = null; |
|
} |
|
console.log(`⏹️ Auto-stopped music in guild ${oldState.guild.name} - no users in voice channel`); |
|
} |
|
} |
|
} |
|
}); |
|
|
|
client.login(token).catch(error => { |
|
console.error(`❌ Failed to login Client ${index + 1}:`, error); |
|
}); |
|
}); |
|
|
|
export { clients, commands, queues }; |
|
|
|
process.on('unhandledRejection', error => { |
|
console.error('❗ Unhandled promise rejection:', error); |
|
}); |
|
process.on('uncaughtException', error => { |
|
console.error('❗ Uncaught exception:', error); |
|
}); |