تخطَّ إلى المحتوى
ARAB CODEمجتمع المطورين العرب

امر بحث

javascriptv1MITنُشر ١٧ أغسطس ٢٠٢٦· ♥ 0 · ⬇ 1 · 💬 0

امر بحث يجلب 5 الي 6 فيديوهات من اي موقع مع امكانيه تثبيتهم

import { spawn } from 'child_process';
import fs from 'fs';
import path from 'path';
import axios from 'axios';
import * as cheerio from 'cheerio';

// 🌑 تخزين مؤقت للروابط والبحث (مع تنظيف تلقائي)
const tempStorage = new Map();
const userSessions = new Map();

// تنظيف الذاكرة كل 30 دقيقة
setInterval(() => {
    const now = Date.now();
    for (const [key, val] of userSessions) {
        if (now - val.time > 30 * 60 * 1000) {
            userSessions.delete(key);
            // clean associated tempStorage
            for (const [k] of tempStorage) {
                if (k.includes(key)) tempStorage.delete(k);
            }
        }
    }
}, 10 * 60 * 1000);

// 🌐 اكتشاف اللغة
function detectLanguage(input) {
    const arabicRegex = /[\u0600-\u06FF]/;
    if (!input) return 'ar';
    if (arabicRegex.test(input)) return 'ar';
    return 'en';
}

// 🔍 كشف المنصة
function detectPlatform(url) {
    if (url.includes('youtube.com') || url.includes('youtu.be')) return 'YouTube ▶️';
    if (url.includes('tiktok.com')) return 'TikTok 🎵';
    if (url.includes('instagram.com')) return 'Instagram 📸';
    if (url.includes('facebook.com') || url.includes('fb.watch')) return 'Facebook 📘';
    if (url.includes('twitter.com') || url.includes('x.com')) return 'Twitter/X 🐦';
    return 'موقع الويب 🌐';
}

// 🎬 البحث بطريقة 1: yt-dlp
async function searchWithYtdlp(query) {
    try {
        const args = ['--dump-json', '--playlist-end', '10', '--no-warnings', `ytsearch10:${query}`];
        const result = await ytDlpExec(args);
        return result.map(item => ({
            title: item.title,
            url: item.webpage_url || item.url || item.original_url,
            thumbnail: item.thumbnail,
            duration: item.duration ? formatSeconds(item.duration) : '0:00',
            views: item.view_count || 0,
            channel: item.uploader || item.channel || 'Unknown',
            source: 'ytdlp'
        }));
    } catch (e) {
        console.log("ytdlp failed:", e.message);
        return [];
    }
}

// 🎬 البحث بطريقة 2: Web Scraping (YouTube HTML)
async function searchWithScraping(query) {
    try {
        const url = `https://www.youtube.com/results?search_query=${encodeURIComponent(query)}`;
        const { data } = await axios.get(url, {
            headers: {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Accept-Language': 'en-US,en;q=0.9'
            },
            timeout: 10000
        });

        const $ = cheerio.load(data);
        const results = [];

        const scriptTag = $('script').filter((i, el) => {
            return $(el).html()?.includes('var ytInitialData');
        }).first();

        if (scriptTag.length) {
            const html = scriptTag.html();
            const match = html.match(/var ytInitialData = (.+?);<\/script>/);
            if (!match) return [];
            const jsonData = JSON.parse(match[1]);
            const videos = jsonData.contents?.twoColumnSearchResultsRenderer?.primaryContents?.sectionListRenderer?.contents[0]?.itemSectionRenderer?.contents || [];

            videos.forEach((item, idx) => {
                if (idx >= 10) return;
                const video = item.videoRenderer;
                if (video) {
                    results.push({
                        title: video.title?.runs?.[0]?.text || 'Unknown',
                        url: `https://youtube.com/watch?v=${video.videoId}`,
                        thumbnail: video.thumbnail?.thumbnails?.pop()?.url || '',
                        duration: video.lengthText?.simpleText || '0:00',
                        views: video.viewCountText?.simpleText || '0',
                        channel: video.ownerText?.runs?.[0]?.text || 'Unknown',
                        source: 'scraping'
                    });
                }
            });
        }
        return results;
    } catch (e) {
        console.log("scraping failed:", e.message);
        return [];
    }
}

// 🎬 البحث بطريقة 3: Invidious API
async function searchWithInvidious(query) {
    const instances = [
        'https://vid.puffyan.us',
        'https://inv.riverside.rocks',
        'https://yt.artemislena.eu',
        'https://iv.nboeck.de',
        'https://iv.datura.network'
    ];

    const results = [];

    for (const instance of instances) {
        try {
            const { data } = await axios.get(`${instance}/api/v1/search`, {
                params: { q: query },
                timeout: 8000
            });

            data.slice(0, 10).forEach(video => {
                results.push({
                    title: video.title,
                    url: `https://youtube.com/watch?v=${video.videoId}`,
                    thumbnail: video.videoThumbnails?.[0]?.url || '',
                    duration: formatSeconds(video.lengthSeconds),
                    views: video.viewCount || 0,
                    channel: video.author || 'Unknown',
                    source: 'invidious'
                });
            });

            if (results.length > 0) break;
        } catch (e) { continue; }
    }
    return results;
}

// 🎬 أمر البحث الرئيسي
async function searchCommand(m, { conn, bot, text }) {
    try {
        if (!text) return m.reply("*🌑 ~ اكتب اسم البحث يا ظل ~ 💀*");

        const loadingMsg = await m.reply("👁️ ~ جاري البحث في ظلال يوتيوب بـ 3 طرق...");

        let results = [];

        if (results.length === 0) results = await searchWithYtdlp(text);
        if (results.length === 0) results = await searchWithScraping(text);
        if (results.length === 0) results = await searchWithInvidious(text);

        if (results.length === 0) {
            await conn.sendMessage(m.chat, { delete: loadingMsg.key }).catch(() => {});
            return m.reply("*💀 ~ فشل البحث في جميع الطرق ~*\n*جرب لاحقاً أو غيّر كلمة البحث*");
        }

        await conn.sendMessage(m.chat, { delete: loadingMsg.key }).catch(() => {});

        const sessionId = `${m.chat}_${m.sender}`;
        userSessions.set(sessionId, {
            results: results,
            query: text,
            time: Date.now()
        });

        const cards = results.slice(0, 10).map((item, index) => {
            const linkId = `dl_${sessionId}_${index}`;
            tempStorage.set(linkId, item.url);

            return {
                imageUrl: item.thumbnail || 'https://i.postimg.cc/4yHqxvRQ/IMG-20260530-WA0072.jpg',
                bodyText: `*${item.title || 'Unknown'}*\n\n⏱️ ${item.duration || 'N/A'} • 👁️ ${formatViews(item.views)} • 👤 ${item.channel || 'Unknown'}`,
                footerText: `${detectPlatform(item.url)} • #${index + 1}`,
                buttons: [
                    {
                        name: 'cta_url',
                        params: { display_text: '▶️╎ مـشـاهـدة', url: item.url }
                    },
                    {
                        name: 'cta_copy',
                        params: { display_text: '📋╎ نـسـخ', copy_code: item.url }
                    },
                    {
                        name: 'quick_reply',
                        params: {
                            display_text: '⬇️╎ تـنـزيـل',
                            id: `.يوتيوب ${item.url}`
                        }
                    }
                ]
            };
        });

        return await conn.sendCarousel(m.chat, {
            headerText: `🌑 نتائج بحث ظل الظلام → *[ ${text} ]*`,
            globalFooterText: `◇ 𝑩𝒐𝒕 𝑺𝒉𝒂𝒅𝒐𝒘 ◇`,
            cards: cards,
            mentions: [m.sender],
            newsletter: {
                name: '◇ 𝑺𝒉𝒂𝒅𝒐𝒘 𝑮𝒂𝒕𝒆 ◇',
                jid: '120363409792989178@newsletter'
            }
        });

    } catch (error) {
        console.error(error);
        m.react("💀");
        return m.reply("*💀 ~ خلل في طاقة الظل ~*");
    }
}

// 🛠️ دوال مساعدة
function ytDlpExec(args) {
    return new Promise((resolve, reject) => {
        const ytdlp = spawn('yt-dlp', args, { stdio: ['ignore', 'pipe', 'pipe'] });
        let output = '';
        let errorOut = '';

        ytdlp.stdout.on('data', (data) => { output += data.toString(); });
        ytdlp.stderr.on('data', (data) => { errorOut += data.toString(); });

        ytdlp.on('close', (code) => {
            if (code !== 0 && output.trim().length === 0) {
                return reject(new Error(errorOut || 'yt-dlp failed'));
            }
            try {
                const lines = output.trim().split('\n').filter(l => l.trim().startsWith('{'));
                resolve(lines.map(line => JSON.parse(line)));
            } catch (e) {
                resolve([]);
            }
        });

        ytdlp.on('error', (err) => reject(err));
    });
}

function formatSeconds(sec) {
    if (sec === undefined || sec === null) return '0:00';
    const num = parseInt(sec);
    if (isNaN(num)) return '0:00';
    const m = Math.floor(num / 60);
    const s = num % 60;
    return `${m}:${s.toString().padStart(2, '0')}`;
}

function formatViews(count) {
    if (!count) return '0';
    const num = typeof count === 'string' ? parseInt(count.toString().replace(/[^0-9]/g, '')) : parseInt(count);
    if (isNaN(num)) return count.toString();
    if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
    if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
    return num.toString();
}

// 📋 تعريف الأمر
searchCommand.category = "search";
searchCommand.command = ["بحث", "فيديو", "yt", "search", "youtube", "يوتيوب_بحث"];
searchCommand.desc = "بحث يوتيوب بـ 3 طرق (yt-dlp + Scraping + API)";

export default searchCommand;

التعليقات (0)

سجّل الدخول للتعليق.