Skip to content

Instantly share code, notes, and snippets.

@taiapi
Created July 20, 2025 05:09
Show Gist options
  • Select an option

  • Save taiapi/4186f7dfde9d1d9ccacaef1b4015a6fc to your computer and use it in GitHub Desktop.

Select an option

Save taiapi/4186f7dfde9d1d9ccacaef1b4015a6fc to your computer and use it in GitHub Desktop.
Upload lệnh sing
const axios = require("axios");
const Youtube = require("youtube-search-api");
const { createReadStream, unlinkSync } = require("fs-extra");
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function getDownloadUrlFromOceansaver(link, maxRetries = 5, retryDelayMs = 5000) {
    if (!link) throw new Error("Thiếu link YouTube");
    let taskId = null;
    let attempts = 0;
    try {
        const resDownload = await axios.get("https://p.oceansaver.in/ajax/download.php", {
            params: {
                copyright: 0,
                format: "mp3",
                url: link,
                api: "30de256ad09118bd6b60a13de631ae2cea6e5f9d" // API key mẫu
            },
            headers: {
                "referer": "https://y2meta.is",
                "origin": "https://y2meta.is",
                "user-agent": "Mozilla/5.0"
            }
        });
        const downloadResult = resDownload.data;
        taskId = downloadResult?.id;
        if (!taskId) {
            throw new Error("Không lấy được ID xử lý từ API. Phản hồi: " + JSON.stringify(downloadResult));
        }
    } catch (error) {
        throw new Error(`Lỗi khi lấy ID xử lý từ API: ${error.message}`);
    }
    while (attempts < maxRetries) {
        try {
            if (attempts > 0) {
                await sleep(retryDelayMs);
            }
            const resProgress = await axios.get(`https://p.oceansaver.in/api/progress`, {
                params: { id: taskId },
                headers: {
                    "referer": "https://y2meta.is",
                    "origin": "https://y2meta.is",
                    "user-agent": "Mozilla/5.0"
                }
            });
            const progressData = resProgress.data;
            if (progressData.success === 1 && progressData.download_url) {
                return { download_url: progressData.download_url };
            } else if (progressData.progress < 1000) {
                attempts++;
                console.log(`Video vẫn đang được xử lý. Thử lại lần ${attempts}/${maxRetries}...`);
            } else {
                throw new Error(`Không lấy được link tải. Trạng thái: ${progressData.status}. Phản hồi: ` + JSON.stringify(progressData));
            }
        } catch (error) {
            if (!error.message.includes("Video vẫn đang được xử lý")) {
                throw new Error(`Lỗi khi gọi API progress: ${error.message}`);
            }
            attempts++;
            console.log(`Lỗi tạm thời khi gọi API progress. Thử lại lần ${attempts}/${maxRetries}...`);
        }
    }
    throw new Error(`Đã thử lại ${maxRetries} lần nhưng video vẫn chưa xử lý xong hoặc không lấy được link tải.`);
}
module.exports.config = {
    name: "sing",
    version: "2.2.0",
    hasPermssion: 0,
    credits: "D-Jukie & gấu",
    description: "Phát nhạc thông qua link YouTube hoặc từ khoá tìm kiếm bằng API.",
    commandCategory: "Phương tiện",
    usages: "[tên bài hát]",
    cooldowns: 5,
};
module.exports.convertHMS = function(value) {
    const sec = parseInt(value, 10);
    let hours = Math.floor(sec / 3600);
    let minutes = Math.floor((sec - (hours * 3600)) / 60);
    let seconds = sec - (hours * 3600) - (minutes * 60);
    if (hours < 10) hours = "0" + hours;
    if (minutes < 10) minutes = "0" + minutes;
    if (seconds < 10) seconds = "0" + seconds;
    return (hours != "00" ? hours + ":" : "") + minutes + ":" + seconds;
};
async function sendMusic(api, event, youtubeLink, title, duration) {
    try {
        api.sendMessage("⏳ Đang xử lý yêu cầu...", event.threadID);
        const timestart = Date.now();
        const { download_url } = await getDownloadUrlFromOceansaver(youtubeLink);
        const { data: stream } = await axios.get(download_url, { responseType: "stream" });
        const processingTime = Math.floor((Date.now() - timestart) / 1000);
        const timeNow = new Date().toLocaleString("vi-VN", { timeZone: "Asia/Ho_Chi_Minh", hour: "2-digit", minute: "2-digit", second: "2-digit" });
        const msg = {
            body: `🎬 Tiêu đề: ${title}\n⏱️ Thời lượng: ${duration}\n⏳ Thời gian xử lý: ${processingTime} giây\n⏰ Lúc: ${timeNow}`,
            attachment: stream
        };
        api.sendMessage(msg, event.threadID);
    } catch (error) {
        console.error("Lỗi trong quá trình xử lý nhạc:", error);
        api.sendMessage(`❌ Đã xảy ra lỗi: ${error.message}`, event.threadID);
    }
}
module.exports.run = async function({ api, event, args }) {
    if (args.length === 0) {
        return api.sendMessage("⚠️ Vui lòng nhập tên bài hát hoặc link YouTube!", event.threadID, event.messageID);
    }
    const keywordSearch = args.join(" ");
    if (keywordSearch.includes("https://")) {
        try {
            const videoInfo = (await Youtube.GetListByKeyword(keywordSearch, false, 1)).items[0];
            if (!videoInfo) {
                return api.sendMessage("❌ Không tìm thấy thông tin video từ link này.", event.threadID);
            }
            await sendMusic(api, event, keywordSearch, videoInfo.title, videoInfo.length.simpleText);
        } catch (e) {
            console.error(e);
            api.sendMessage("❌ Đã có lỗi xảy ra khi lấy thông tin video từ link.", event.threadID);
        }
    } else {
        try {
            api.sendMessage("", event.threadID, event.messageID);
            const searchResults = (await Youtube.GetListByKeyword(keywordSearch, false, 10)).items;
            if (!searchResults || searchResults.length === 0) {
                return api.sendMessage("❌ Không tìm thấy kết quả phù hợp.", event.threadID);
            }
            let msg = "";
            const links = [];
            const titles = [];
            const durations = [];
            for (let i = 0; i < searchResults.length; i++) {
                const value = searchResults[i];
                const videoId = typeof value.id === "string" ? value.id : value.id.videoId;
                links.push(videoId);
                titles.push(value.title);
                durations.push(value.length.simpleText);
                msg += `${i + 1}. ${value.title}\n - Kênh: ${value.channelTitle}\n - Thời lượng: ${value.length.simpleText}\n\n`;
            }
            const body = `📝 Có ${links.length} kết quả:\n\n${msg}👉 Vui lòng reply tin nhắn này với số thứ tự bài hát bạn muốn chọn.`;
            api.sendMessage(body, event.threadID, (error, info) => {
                if (error) return console.error(error);
                global.client.handleReply.push({
                    type: "reply",
                    name: module.exports.config.name,
                    messageID: info.messageID,
                    author: event.senderID,
                    links,
                    titles,
                    durations
                });
            });
        } catch (e) {
            console.error(e);
            api.sendMessage("❌ Đã có lỗi xảy ra khi tìm kiếm.", event.threadID);
        }
    }
};
module.exports.handleReply = async function({ api, event, handleReply }) {
    if (event.senderID !== handleReply.author) {
        return api.sendMessage("⛔ Bạn không phải người yêu cầu, không thể chọn.", event.threadID, event.messageID);
    }
    const choice = parseInt(event.body);
    if (isNaN(choice) || choice < 1 || choice > handleReply.links.length) {
        return api.sendMessage("⚠️ Lựa chọn không hợp lệ. Vui lòng chọn một số trong danh sách.", event.threadID, event.messageID);
    }
    api.unsendMessage(handleReply.messageID);
    const videoId = handleReply.links[choice - 1];
    const youtubeLink = `https://www.youtube.com/watch?v=${videoId}`;
    const title = handleReply.titles[choice - 1];
    const duration = handleReply.durations[choice - 1];
    await sendMusic(api, event, youtubeLink, title, duration);
};
module.exports.getDownloadUrlFromOceansaver = getDownloadUrlFromOceansaver;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment