const { addToQueue, playNextInQueue } = require('../utils/queueManager'); const ytDlpExec = require('yt-dlp-exec'); const { v4: uuidv4 } = require('uuid'); const path = require('path'); const { EmbedBuilder } = require('discord.js'); const fetch = require('node-fetch'); const fs = require('fs'); module.exports = { name: 'play', description: 'Play a song from YouTube, a URL, or an uploaded MP3 file', async execute(message, args) { const searchQuery = args.join(' '); const voiceChannel = message.member.voice.channel; if (!voiceChannel) { return message.reply('You need to be in a voice channel to play music!'); } let url, title, tempFilePath; try { if (message.attachments.size > 0) { const attachment = message.attachments.first(); if (attachment.name.endsWith('.mp3')) { title = attachment.name; tempFilePath = path.join(__dirname, '../utils/tmp', `${uuidv4()}.mp3`); const response = await fetch(attachment.url); const buffer = await response.buffer(); fs.writeFileSync(tempFilePath, buffer); const embed = new EmbedBuilder() .setColor('#0099ff') .setTitle('Now Playing') .setDescription(`**${title}**`) .setFooter({ text: `Requested by ${message.author.username}`, iconURL: message.author.displayAvatarURL() }) .setTimestamp(); message.channel.send({ embeds: [embed] }); addToQueue(message.guild.id, tempFilePath, title); playNextInQueue(message.guild.id, voiceChannel); return; } else { return message.reply('Only MP3 files are supported for uploads.'); } } if (!searchQuery) { return message.reply('Please provide a YouTube link, MP3 link, or a song name.'); } if (isValidURL(searchQuery)) { url = searchQuery; if (url.endsWith('.mp3')) { title = path.basename(url); tempFilePath = path.join(__dirname, '../utils/tmp', `${uuidv4()}.mp3`); const response = await fetch(url); const buffer = await response.buffer(); fs.writeFileSync(tempFilePath, buffer); } else { const info = await ytDlpExec(url, { dumpSingleJson: true }); title = info.title; tempFilePath = path.join(__dirname, '../utils/tmp', `${uuidv4()}.mp3`); await ytDlpExec(url, { cookies: path.join(__dirname, '../cookies.txt'), format: 'bestaudio', output: tempFilePath, quiet: true, }); } } else { const searchResult = await ytDlpExec(`ytsearch:${searchQuery}`, { dumpSingleJson: true, noPlaylist: true, format: 'bestaudio/best', quiet: true, }); url = searchResult.entries[0].webpage_url; title = searchResult.entries[0].title; tempFilePath = path.join(__dirname, '../utils/tmp', `${uuidv4()}.mp3`); await ytDlpExec(url, { cookies: path.join(__dirname, '../cookies.txt'), format: 'bestaudio', output: tempFilePath, quiet: true, }); } const embed = new EmbedBuilder() .setColor('#0099ff') .setTitle('Now Playing') .setDescription(`**${title}**`) .setFooter({ text: `Requested by ${message.author.username}`, iconURL: message.author.displayAvatarURL() }) .setTimestamp(); message.channel.send({ embeds: [embed] }); addToQueue(message.guild.id, tempFilePath, title); playNextInQueue(message.guild.id, voiceChannel); } catch (error) { console.error('yt-dlp error:', error); message.reply('Failed to retrieve or download video. Please try again.'); } }, }; function isValidURL(string) { try { new URL(string); return true; } catch (_) { return false; } }