goat
command
sing
Send a song as audio
0
views
0
likes
0
installs
raw source
const axios = require('axios');
const fs = require('fs-extra');
const path = require('path');
const API_BASE_URL = process.env.SING_API_BASE_URL || "https://noobdevs-apis.onrender.com";
module.exports.config = {
name: "sing",
version: "1.0.0",
author: "Badhon-00",
countDown: 5,
role: 0,
shortDescription: "Send a song as audio",
longDescription: "Searches by song title and sends the matched track as an audio attachment.",
category: "media",
guide: {
en: "{p}sing <song title>"
}
};
module.exports.onStart = async function ({ api, event, args, message }) {
const songName = args.join(" ");
if (!songName) {
return message.reply(
"──────────────────\n" +
"⚠️ MISSING SONG QUERY\n" +
"──────────────────\n" +
"Please provide a song title.\n\n" +
"💡 Example: sing tera mera rishta mashup\n" +
"🎬 For video instead: sing-v <title>\n" +
"──────────────────"
);
}
const searchingMsg = await message.reply(`🔍 Searching: "${songName}"\n⏳ Please wait while fetching track metadata...`);
const cacheFolder = path.join(__dirname, 'cache');
let audioFilePath = null;
const cleanupSearchingMsg = () => {
if (searchingMsg && searchingMsg.messageID) api.unsendMessage(searchingMsg.messageID).catch(() => {});
};
try {
const searchUrl = `${API_BASE_URL}/Melissa/api/v2/NoobDevs/song_search?q=${encodeURIComponent(songName)}`;
const searchRes = await axios.get(searchUrl, { timeout: 20000, validateStatus: () => true });
if (searchRes.status === 404) {
cleanupSearchingMsg();
return message.reply(`❌ Track Search Failed\nNo track found for "${songName}".`);
}
if (searchRes.status !== 200 || !searchRes.data || !searchRes.data.status) {
cleanupSearchingMsg();
const detail = (searchRes.data && (searchRes.data.message || searchRes.data.error)) || `HTTP ${searchRes.status}`;
return message.reply(`❌ Track Search Failed\n${detail}`);
}
const song = searchRes.data;
const streamEndpoint = `${API_BASE_URL}/Melissa/api/v2/NoobDevs/searchaudio?sing=${encodeURIComponent(song.url)}`;
await fs.ensureDir(cacheFolder);
audioFilePath = path.join(cacheFolder, `${Date.now()}_song.mp3`);
const audioResponse = await axios({
method: 'GET',
url: streamEndpoint,
responseType: 'stream',
timeout: 60000,
validateStatus: () => true
});
if (audioResponse.status !== 200) {
let detail = `HTTP ${audioResponse.status}`;
try {
const chunks = [];
for await (const chunk of audioResponse.data) chunks.push(chunk);
const body = JSON.parse(Buffer.concat(chunks).toString('utf8'));
detail = body.error || body.message || detail;
if (body.hint) detail += `\n💡 ${body.hint}`;
} catch (_) { /* not JSON */ }
cleanupSearchingMsg();
return message.reply(`❌ Download Failed\n${detail}`);
}
const fileWriter = fs.createWriteStream(audioFilePath);
audioResponse.data.pipe(fileWriter);
await new Promise((resolve, reject) => {
fileWriter.on('finish', resolve);
fileWriter.on('error', reject);
audioResponse.data.on('error', reject);
});
const stats = await fs.stat(audioFilePath);
if (stats.size === 0) {
throw new Error('Downloaded file is empty — the source stream failed silently.');
}
const replyBody =
"🎵 MELISSA MUSIC PLAYER 🎵\n" +
"────────────────────────\n" +
`🎧 Title: ${song.title}\n` +
`👤 Artist/Channel: ${song.author}\n` +
`⏱️ Duration: ${song.duration}\n` +
`👁️ Views: ${song.views ? String(song.views) : 'N/A'}\n` +
"────────────────────────\n" +
"✨ Audio attached below. Enjoy listening!";
await message.reply({
body: replyBody,
attachment: fs.createReadStream(audioFilePath)
});
cleanupSearchingMsg();
} catch (error) {
console.error(error);
cleanupSearchingMsg();
const isTimeout = error.code === 'ECONNABORTED';
return message.reply(
isTimeout
? `❌ Timed Out\nThe song server took too long to respond. Try again in a moment.`
: `❌ Error Processing Song\n${error.message}`
);
} finally {
if (audioFilePath && await fs.pathExists(audioFilePath)) {
await fs.remove(audioFilePath).catch(() => {});
}
}
};