← back to browse
goat command

ytb

No description

0
views
0
likes
0
installs

Aliases: youtube, yt, ভিডিও

raw source
const axios = require("axios");
const fs = require("fs");
const path = require("path");
const yts = require("yt-search");
const { alldown } = require("shaon-video-downloader");

module.exports = {
    config: {
        name: "ytb",
        aliases: ["youtube", "yt", "ভিডিও"],
        version: "3.1.0",
        author: "SUJON - BOSS",
        countDown: 10,
        role: 0,

        description: {
            bn: "YouTube থেকে ৬টি ভিডিও thumbnail সহ দেখিয়ে পছন্দের ভিডিও download করুন",
            en: "Search 6 YouTube videos with thumbnails and download selected video"
        },

        category: "media",

        guide: {
            bn: "{pn} <ভিডিওর নাম>\nউদাহরণ: {pn} Tum Hi Ho",
            en: "{pn} <video name>\nExample: {pn} Tum Hi Ho"
        }
    },

    langs: {
        bn: {
            noInput:
                "❌ ভিডিওর নাম লিখো!\n\nউদাহরণ:\n&ytb Tum Hi Ho",

            searching:
                "🔎 YouTube-এ খোঁজা হচ্ছে...\n\n⏳ একটু অপেক্ষা করো...",

            noResult:
                "❌ কোনো ভিডিও পাওয়া যায়নি।",

            result:
                "╭━━━〔 🎬 YOUTUBE SEARCH 〕━━━╮\n" +
                "┃\n" +
                "┃ 🎵 ৬টি ভিডিও পাওয়া গেছে\n" +
                "┃\n" +
                "%1" +
                "┃\n" +
                "╰━━━━━━━━━━━━━━━━━━━━━━╯\n\n" +
                "👉 পছন্দের ভিডিওর নম্বর Reply করো\n" +
                "🔢 উদাহরণ: 1",

            invalid:
                "❌ ভুল নম্বর!\n\n👉 শুধু 1 থেকে 6 এর মধ্যে একটি নম্বর Reply করো।",

            downloading:
                "⏳ ভিডিও Download হচ্ছে...\n\n" +
                "🎬 %1\n\n" +
                "📥 Video: MP4\n" +
                "⚡ একটু অপেক্ষা করো...",

            success:
                "╭━━━〔 🎬 SUJON - BOSS 〕━━━╮\n" +
                "┃\n" +
                "┃ 🎥 %1\n" +
                "┃\n" +
                "┃ ✅ Video Download Complete\n" +
                "┃ ❤️ Enjoy!\n" +
                "╰━━━━━━━━━━━━━━━━━━━━╯",

            error:
                "❌ ভিডিও Download করতে সমস্যা হয়েছে।\n\n%1"
        },

        en: {
            noInput:
                "❌ Please enter a video name!\n\nExample:\n&ytb Tum Hi Ho",

            searching:
                "🔎 Searching YouTube...\n\n⏳ Please wait...",

            noResult:
                "❌ No videos found.",

            result:
                "╭━━━〔 🎬 YOUTUBE SEARCH 〕━━━╮\n" +
                "┃\n" +
                "┃ 🎵 6 videos found\n" +
                "┃\n" +
                "%1" +
                "┃\n" +
                "╰━━━━━━━━━━━━━━━━━━━━━━╯\n\n" +
                "👉 Reply with the video number\n" +
                "🔢 Example: 1",

            invalid:
                "❌ Invalid number!\n\n👉 Reply with a number from 1 to 6.",

            downloading:
                "⏳ Downloading video...\n\n" +
                "🎬 %1\n\n" +
                "📥 Video: MP4\n" +
                "⚡ Please wait...",

            success:
                "╭━━━〔 🎬 SUJON - BOSS 〕━━━╮\n" +
                "┃\n" +
                "┃ 🎥 %1\n" +
                "┃\n" +
                "┃ ✅ Video Download Complete\n" +
                "┃ ❤️ Enjoy!\n" +
                "╰━━━━━━━━━━━━━━━━━━━━╯",

            error:
                "❌ Failed to download video.\n\n%1"
        }
    },

    // =====================================================
    // 🔎 YOUTUBE SEARCH
    // =====================================================

    onStart: async function ({
        api,
        event,
        args,
        message,
        getLang
    }) {

        if (!args.length) {
            return message.reply(
                getLang("noInput")
            );
        }

        const query =
            args.join(" ").trim();

        let searchingMessage = null;

        try {

            // =============================================
            // 🔎 SEARCHING MESSAGE
            // =============================================

            searchingMessage =
                await new Promise(
                    (resolve, reject) => {

                        api.sendMessage(
                            getLang("searching"),

                            event.threadID,

                            (err, info) => {

                                if (err) {
                                    reject(err);
                                    return;
                                }

                                resolve(info);
                            },

                            event.messageID
                        );

                    }
                );

            // =============================================
            // 🔍 SEARCH YOUTUBE
            // =============================================

            const search =
                await yts(query);

            if (
                !search ||
                !search.videos ||
                !search.videos.length
            ) {

                if (
                    searchingMessage?.messageID
                ) {

                    try {
                        api.unsendMessage(
                            searchingMessage.messageID,
                            () => {}
                        );
                    } catch {}

                }

                return api.sendMessage(
                    getLang("noResult"),
                    event.threadID,
                    event.messageID
                );
            }

            // =============================================
            // 🎬 TAKE FIRST 6
            // =============================================

            const videos =
                search.videos.slice(0, 6);

            const cacheDir =
                path.join(
                    __dirname,
                    "cache"
                );

            if (!fs.existsSync(cacheDir)) {

                fs.mkdirSync(
                    cacheDir,
                    {
                        recursive: true
                    }
                );

            }

            // =============================================
            // 📝 BUILD LIST
            // =============================================

            let list = "";

            videos.forEach(
                (video, index) => {

                    const duration =
                        video.timestamp ||
                        "Unknown";

                    const author =
                        video.author?.name ||
                        "YouTube";

                    list +=
                        `┃ ${index + 1}. 🎬 ${video.title}\n` +
                        `┃    ⏱️ ${duration}\n` +
                        `┃    👤 ${author}\n` +
                        `┃\n`;
                }
            );

            // =============================================
            // 🖼️ DOWNLOAD THUMBNAILS
            // =============================================

            const attachments = [];

            for (
                let i = 0;
                i < videos.length;
                i++
            ) {

                const video =
                    videos[i];

                try {

                    const thumbnail =
                        video.thumbnail ||
                        `https://i.ytimg.com/vi/${video.videoId}/hqdefault.jpg`;

                    const thumbPath =
                        path.join(
                            cacheDir,
                            `ytb_thumb_${event.threadID}_${Date.now()}_${i}.jpg`
                        );

                    const thumbResponse =
                        await axios.get(
                            thumbnail,
                            {
                                responseType:
                                    "arraybuffer",

                                timeout:
                                    15000,

                                headers: {
                                    "User-Agent":
                                        "Mozilla/5.0"
                                }
                            }
                        );

                    fs.writeFileSync(
                        thumbPath,
                        Buffer.from(
                            thumbResponse.data
                        )
                    );

                    video.__thumbPath =
                        thumbPath;

                    attachments.push(
                        fs.createReadStream(
                            thumbPath
                        )
                    );

                } catch (err) {

                    console.log(
                        "⚠️ Thumbnail error:",
                        err.message
                    );

                }
            }

            // =============================================
            // 📩 SEND SEARCH RESULT
            // =============================================

            const resultBody =
                getLang(
                    "result",
                    list
                );

            const payload = {
                body: resultBody
            };

            if (attachments.length) {
                payload.attachment =
                    attachments;
            }

            return api.sendMessage(
                payload,

                event.threadID,

                (err, info) => {

                    // =====================================
                    // 🗑️ DELETE SEARCHING MESSAGE
                    // =====================================

                    if (
                        searchingMessage?.messageID
                    ) {

                        try {

                            api.unsendMessage(
                                searchingMessage.messageID,
                                () => {}
                            );

                        } catch {}

                    }

                    if (err) {

                        console.error(
                            "❌ YTB result error:",
                            err
                        );

                        return;
                    }

                    // =====================================
                    // ⭐ REGISTER REPLY
                    // =====================================

                    global.GoatBot.onReply.set(
                        info.messageID,
                        {
                            commandName:
                                module.exports.config.name,

                            messageID:
                                info.messageID,

                            author:
                                event.senderID,

                            type:
                                "ytbSelect",

                            videos:
                                videos
                        }
                    );

                    console.log(
                        "✅ YTB Reply Registered:",
                        info.messageID
                    );

                    // =====================================
                    // 🧹 THUMBNAIL CLEANUP
                    // =====================================

                    setTimeout(
                        () => {

                            for (
                                const video of videos
                            ) {

                                if (
                                    video.__thumbPath &&
                                    fs.existsSync(
                                        video.__thumbPath
                                    )
                                ) {

                                    try {

                                        fs.unlinkSync(
                                            video.__thumbPath
                                        );

                                    } catch {}

                                }

                            }

                        },
                        120000
                    );

                },

                event.messageID
            );

        } catch (error) {

            console.error(
                "❌ YTB Search Error:",
                error
            );

            if (
                searchingMessage?.messageID
            ) {

                try {

                    api.unsendMessage(
                        searchingMessage.messageID,
                        () => {}
                    );

                } catch {}

            }

            return api.sendMessage(
                getLang(
                    "error",
                    error.message
                ),
                event.threadID,
                event.messageID
            );
        }
    },

    // =====================================================
    // 🔢 REPLY → SELECT VIDEO
    // =====================================================

    onReply: async function ({
        api,
        event,
        Reply,
        getLang
    }) {

        if (
            !Reply ||
            Reply.type !== "ytbSelect"
        ) {
            return;
        }

        // =============================================
        // 👤 ONLY ORIGINAL USER
        // =============================================

        if (
            Reply.author &&
            event.senderID !== Reply.author
        ) {
            return;
        }

        const text =
            event.body?.trim();

        if (!text) {
            return;
        }

        const number =
            parseInt(text, 10);

        // =============================================
        // 🔢 VALIDATE NUMBER
        // =============================================

        if (
            !Number.isInteger(number) ||
            number < 1 ||
            number > Reply.videos.length
        ) {

            return api.sendMessage(
                getLang("invalid"),
                event.threadID,
                event.messageID
            );
        }

        const video =
            Reply.videos[number - 1];

        if (!video) {

            return api.sendMessage(
                getLang(
                    "error",
                    "Video information পাওয়া যায়নি।"
                ),
                event.threadID,
                event.messageID
            );
        }

        const title =
            video.title ||
            "YouTube Video";

        const youtubeUrl =
            video.url ||
            `https://www.youtube.com/watch?v=${video.videoId}`;

        const cacheDir =
            path.join(
                __dirname,
                "cache"
            );

        if (!fs.existsSync(cacheDir)) {

            fs.mkdirSync(
                cacheDir,
                {
                    recursive: true
                }
            );

        }

        const filePath =
            path.join(
                cacheDir,
                `ytb_${event.threadID}_${Date.now()}.mp4`
            );

        let downloadingMessage = null;

        try {

            // =============================================
            // 🗑️ REMOVE REPLY REGISTRY
            // =============================================

            try {

                global.GoatBot.onReply.delete(
                    Reply.messageID
                );

            } catch {}

            // =============================================
            // ⏳ DOWNLOADING MESSAGE
            // =============================================

            downloadingMessage =
                await new Promise(
                    (resolve, reject) => {

                        api.sendMessage(
                            getLang(
                                "downloading",
                                title
                            ),

                            event.threadID,

                            (err, info) => {

                                if (err) {
                                    reject(err);
                                    return;
                                }

                                resolve(info);
                            },

                            event.messageID
                        );

                    }
                );

            // =============================================
            // 🎬 SHAON ALLDOWN
            // =============================================

            console.log(
                "================================="
            );

            console.log(
                "🎬 YTB VIDEO DOWNLOAD"
            );

            console.log(
                "🎵 Title:",
                title
            );

            console.log(
                "🔗 URL:",
                youtubeUrl
            );

            const data =
                await alldown(
                    youtubeUrl
                );

            console.log(
                "📦 SHAON RESULT:",
                JSON.stringify(
                    data,
                    null,
                    2
                )
            );

            if (
                !data ||
                data.status !== true
            ) {

                throw new Error(
                    data?.message ||
                    "Downloader failed."
                );

            }

            // =============================================
            // 🎥 IMPORTANT
            //
            // SHAON 1.0.1 এর response অনুযায়ী
            // VIDEO URL হলো data.url
            //
            // data.audio = শুধু AUDIO
            // তাই audio কখনো ব্যবহার করা হচ্ছে না।
            // =============================================

            const videoDownloadUrl =
                typeof data.url === "string"
                    ? data.url
                    : null;

            if (!videoDownloadUrl) {

                throw new Error(
                    "Video URL পাওয়া যায়নি।"
                );

            }

            // =============================================
            // 🛡️ MAKE SURE IT IS VIDEO
            // =============================================

            const urlLower =
                videoDownloadUrl.toLowerCase();

            if (
                urlLower.includes(
                    "mime=audio"
                )
            ) {

                throw new Error(
                    "Downloader audio URL দিয়েছে, video নয়।"
                );

            }

            if (
                data.ext &&
                data.ext !== "mp4"
            ) {

                console.log(
                    "⚠️ Extension:",
                    data.ext
                );

            }

            console.log(
                "🎥 VIDEO URL FOUND"
            );

            console.log(
                "📺 Quality:",
                data.quality ||
                "Unknown"
            );

            // =============================================
            // 📥 DOWNLOAD MP4 VIDEO
            // =============================================

            let response;

            try {

                response =
                    await axios.get(
                        videoDownloadUrl,
                        {
                            responseType:
                                "arraybuffer",

                            timeout:
                                300000,

                            maxContentLength:
                                Infinity,

                            maxBodyLength:
                                Infinity,

                            headers: {
                                "User-Agent":
                                    "Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36 Chrome/120 Mobile Safari/537.36",

                                "Accept":
                                    "*/*",

                                "Referer":
                                    "https://www.youtube.com/"
                            }
                        }
                    );

            } catch (firstError) {

                console.log(
                    "⚠️ First video request failed:",
                    firstError.message
                );

                // =========================================
                // 🔁 RETRY WITHOUT HEADERS
                // =========================================

                response =
                    await axios.get(
                        videoDownloadUrl,
                        {
                            responseType:
                                "arraybuffer",

                            timeout:
                                300000,

                            maxContentLength:
                                Infinity,

                            maxBodyLength:
                                Infinity
                        }
                    );
            }

            if (
                !response ||
                !response.data
            ) {

                throw new Error(
                    "Video download failed."
                );

            }

            // =============================================
            // 📄 CHECK CONTENT TYPE
            // =============================================

            const contentType =
                String(
                    response.headers[
                        "content-type"
                    ] || ""
                ).toLowerCase();

            if (
                contentType.includes(
                    "text/html"
                )
            ) {

                throw new Error(
                    "YouTube video এর বদলে HTML response এসেছে।"
                );

            }

            // =============================================
            // 💾 SAVE MP4
            // =============================================

            fs.writeFileSync(
                filePath,
                Buffer.from(
                    response.data
                )
            );

            // =============================================
            // 📊 CHECK FILE
            // =============================================

            if (
                !fs.existsSync(
                    filePath
                )
            ) {

                throw new Error(
                    "Video file তৈরি হয়নি।"
                );

            }

            const stats =
                fs.statSync(
                    filePath
                );

            if (
                stats.size < 50000
            ) {

                throw new Error(
                    "Video file খুব ছোট/invalid হয়েছে।"
                );

            }

            console.log(
                `✅ VIDEO SAVED: ${(stats.size / 1024 / 1024).toFixed(2)} MB`
            );

            // =============================================
            // 🎥 SEND VIDEO
            // =============================================

            await new Promise(
                (resolve, reject) => {

                    api.sendMessage(
                        {
                            body:
                                getLang(
                                    "success",
                                    title
                                ),

                            attachment:
                                fs.createReadStream(
                                    filePath
                                )
                        },

                        event.threadID,

                        (err, info) => {

                            if (err) {
                                reject(err);
                                return;
                            }

                            resolve(info);
                        },

                        event.messageID
                    );

                }
            );

            console.log(
                "✅ VIDEO SENT SUCCESSFULLY"
            );

            // =============================================
            // 🗑️ AUTO DELETE DOWNLOADING MESSAGE
            // =============================================

            if (
                downloadingMessage?.messageID
            ) {

                try {

                    api.unsendMessage(
                        downloadingMessage.messageID,
                        () => {}
                    );

                } catch {}

            }

            // =============================================
            // 🗑️ AUTO DELETE SEARCH RESULT
            // =============================================

            if (
                Reply.messageID
            ) {

                try {

                    api.unsendMessage(
                        Reply.messageID,
                        () => {}
                    );

                } catch {}

            }

            // =============================================
            // 🧹 DELETE LOCAL VIDEO
            // =============================================

            setTimeout(
                () => {

                    if (
                        fs.existsSync(
                            filePath
                        )
                    ) {

                        try {

                            fs.unlinkSync(
                                filePath
                            );

                            console.log(
                                "🧹 Video cache deleted."
                            );

                        } catch {}

                    }

                },
                30000
            );

        } catch (error) {

            console.error(
                "❌ YTB VIDEO ERROR:",
                error
            );

            // =============================================
            // 🗑️ DELETE DOWNLOADING MESSAGE
            // =============================================

            if (
                downloadingMessage?.messageID
            ) {

                try {

                    api.unsendMessage(
                        downloadingMessage.messageID,
                        () => {}
                    );

                } catch {}

            }

            // =============================================
            // 🧹 DELETE BROKEN FILE
            // =============================================

            if (
                fs.existsSync(
                    filePath
                )
            ) {

                try {

                    fs.unlinkSync(
                        filePath
                    );

                } catch {}

            }

            return api.sendMessage(
                getLang(
                    "error",
                    error.message
                ),
                event.threadID,
                event.messageID
            );
        }
    }
};

View raw file