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

Insta-dl

javascriptv1MITنُشر ١٦ أكتوبر ٢٠٢٦· ♥ 1 · ⬇ 2 · 💬 1

تحميل فيديوهات و صور انستجرام ب جودات مختلفه

import fetch from 'node-fetch';
import crypto from 'node:crypto';
import {
    prepareWAMessageMedia,
    generateWAMessageFromContent,
    proto
} from '@whiskeysockets/baileys';

const API_BASE = 'https://api.savefromins.com/api/contentsite_api';
const API_DOMAIN = 'api-ak.savefromins.com';
const API_AUTH = 'f8a1c2d4';
const API_ORIGIN = 'https://igvideodownloader.net';
const MAX_INLINE_MB = 90;
const REQUEST_TIMEOUT_MS = 60_000;

function aesKeys() {
    
    return [
        `${API_AUTH}${API_AUTH}${API_AUTH}${API_AUTH}`,
        'rz18efAXUbdiaO7k'
    ];
}

function decryptApiData(value) {
    if (typeof value !== 'string' || !value.trim()) return value;

    let lastError;
    for (const keyText of aesKeys()) {
        try {
            const key = Buffer.from(keyText, 'utf8');
            const iv = key.subarray(0, 16);
            const decipher = crypto.createDecipheriv(
                key.length === 16 ? 'aes-128-cbc' : key.length === 24 ? 'aes-192-cbc' : 'aes-256-cbc',
                key,
                iv
            );
            decipher.setAutoPadding(false);
            const plain = Buffer.concat([
                decipher.update(Buffer.from(value.trim(), 'base64')),
                decipher.final()
            ]).toString('utf8').replace(/\0+$/g, '');
            return JSON.parse(plain);
        } catch (error) {
            lastError = error;
        }
    }

    throw new Error(`تعذر فك استجابة API: ${lastError?.message || 'مفتاح غير صالح'}`);
}

async function readApiResponse(response) {
    const raw = await response.text();
    if (!response.ok) throw new Error(`API HTTP ${response.status}`);

    let parsed;
    try {
        parsed = JSON.parse(raw);
    } catch {
        parsed = raw;
    }

    
    if (parsed && typeof parsed === 'object' && typeof parsed.data === 'string') {
        try {
            parsed.data = decryptApiData(parsed.data);
        } catch {
            
            if (parsed.status === 1) throw new Error('استجابة API مشفرة وغير قابلة للقراءة');
        }
    } else if (typeof parsed === 'string') {
        try {
            parsed = decryptApiData(parsed);
        } catch {
            
        }
    }

    return parsed;
}

function apiHeaders() {
    return {
        accept: '*/*',
        'accept-language': 'ar-SD,ar;q=0.9,en;q=0.8',
        'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
        origin: API_ORIGIN,
        referer: `${API_ORIGIN}/`,
        'user-agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Mobile Safari/537.36'
    };
}

async function apiPost(path, data) {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);

    try {
        const body = new URLSearchParams({
            auth: API_AUTH,
            domain: API_DOMAIN,
            ...data
        });
        const response = await fetch(`${API_BASE}/${path}`, {
            method: 'POST',
            headers: apiHeaders(),
            body,
            signal: controller.signal
        });
        return await readApiResponse(response);
    } catch (error) {
        if (error.name === 'AbortError') throw new Error('انتهت مهلة الاتصال بخدمة التحليل');
        throw error;
    } finally {
        clearTimeout(timer);
    }
}

function safeText(value, fallback = '') {
    return String(value || fallback).replace(/[|#\r\n]/g, ' ').trim();
}

function mediaType(resource, parentType = '') {
    const type = String(resource?.type || parentType || '').toLowerCase();
    const format = String(resource?.format || '').toLowerCase();
    if (type === 'audio' || format === 'mp3' || format === 'm4a' || format === 'aac') return 'audio';
    if (type === 'picture' || type === 'image' || ['jpg', 'jpeg', 'png', 'webp', 'gif'].includes(format)) return 'image';
    return 'video';
}

function encodeDownloadPayload(payload) {
    return Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url');
}

function decodeDownloadPayload(text) {
    const value = String(text || '').trim();
    try {
        return JSON.parse(Buffer.from(value, 'base64url').toString('utf8'));
    } catch {
        // توافق مع الأزرار القديمة التي كانت تستخدم type|url|title|format.
        const [type, url, title, format] = value.split('|');
        return { type, url, title, format };
    }
}

function buildOptions(data, usedPrefix) {
    const options = [];
    const seen = new Set();
    const mediaItems = Array.isArray(data?.media) ? data.media : [];

    for (const item of mediaItems) {
        const resources = Array.isArray(item?.resources) ? item.resources : [];
        for (const resource of resources) {
            const url = resource?.download_url || '';
            const resourceContent = resource?.resource_content || '';
            if (!url && !resourceContent) continue;

            const type = mediaType(resource, item?.type);
            const format = safeText(resource?.format, type === 'audio' ? 'mp3' : type === 'image' ? 'jpg' : 'mp4');
            const quality = safeText(resource?.quality, 'HD');
            const identity = url || resourceContent;
            if (seen.has(identity)) continue;
            seen.add(identity);

            const size = Number(resource?.size);
            const sizeLabel = Number.isFinite(size) && size > 0
                ? `${(size / (1024 * 1024)).toFixed(2)} MB`
                : 'تحميل مباشر';

            const payload = encodeDownloadPayload({
                type,
                url,
                title: safeText(data?.title, 'Instagram Media'),
                format,
                resourceContent
            });

            options.push({
                title: `${type === 'audio' ? '🎵' : type === 'image' ? '🖼️' : '🎬'} ${quality} · ${format.toUpperCase()}`,
                description: `الحجم: ${sizeLabel}`,
                id: `${usedPrefix}dl_ig_media ${payload}`
            });
        }
    }

    return options.slice(0, 10);
}

async function fetchMedia(url) {
    const response = await fetch(url, {
        method: 'GET',
        redirect: 'follow',
        headers: {
            'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 Chrome/135.0.0.0 Mobile Safari/537.36',
            accept: '*/*',
            referer: 'https://www.instagram.com/'
        },
        signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
    });

    if (!response.ok) throw new Error(`رابط التحميل أعاد HTTP ${response.status}`);
    const contentType = response.headers.get('content-type') || '';
    if (/text\/html|application\/json/i.test(contentType)) {
        throw new Error('رابط التحميل منتهي أو أعاد صفحة حماية بدلاً من الميديا');
    }

    const buffer = Buffer.from(await response.arrayBuffer());
    if (!buffer.length) throw new Error('الملف المسترجع فارغ');
    return { buffer, contentType };
}

async function sendDownloadedMedia(m, conn, payload) {
    if (!payload?.url) throw new Error('هذا الخيار يحتاج معالجة تحميل إضافية وغير متاح حالياً');

    const { buffer, contentType } = await fetchMedia(payload.url);
    const sizeMb = buffer.length / (1024 * 1024);
    const type = payload.type || mediaType({ format: payload.format });
    const format = String(payload.format || '').toLowerCase();
    const title = safeText(payload.title, 'Instagram Media');

    if (type === 'image') {
        await conn.sendMessage(m.chat, {
            image: buffer,
            caption: `📸 ${title}`
        }, { quoted: m });
        return;
    }

    if (type === 'audio') {
        const mimetype = contentType.startsWith('audio/') ? contentType : 'audio/mpeg';
        if (sizeMb <= MAX_INLINE_MB) {
            await conn.sendMessage(m.chat, { audio: buffer, mimetype, ptt: false }, { quoted: m });
        } else {
            await conn.sendMessage(m.chat, {
                document: buffer,
                mimetype,
                fileName: `Instagram_Audio.${format || 'mp3'}`,
                caption: `🎵 الحجم: ${sizeMb.toFixed(2)} MB`
            }, { quoted: m });
        }
        return;
    }

    const mimetype = contentType.startsWith('video/') ? contentType : 'video/mp4';
    if (sizeMb <= MAX_INLINE_MB) {
        await conn.sendMessage(m.chat, {
            video: buffer,
            mimetype,
            caption: `🎬 ${title}\n📊 الحجم: ${sizeMb.toFixed(2)} MB`
        }, { quoted: m });
    } else {
        await conn.sendMessage(m.chat, {
            document: buffer,
            mimetype,
            fileName: `Instagram_Video.${format || 'mp4'}`,
            caption: `📦 أُرسل كملف لأن الحجم ${sizeMb.toFixed(2)} MB`
        }, { quoted: m });
    }
}

const handler = async (m, { conn, text, usedPrefix, command }) => {
    if (command === 'dl_ig_media') {
        if (!text) return;
        await m.react('⏳');
        try {
            await sendDownloadedMedia(m, conn, decodeDownloadPayload(text));
            await m.react('✅');
        } catch (error) {
            console.error('[ig-downloader]', error);
            await m.react('❌');
            await m.reply(`❌ فشل التحميل: ${error.message || 'الرابط منتهي أو محمي.'}`);
        }
        return;
    }

    const link = String(text || '').trim();
    if (!link) {
        return m.reply(`⚠️ أرسل رابط إنستغرام بعد الأمر.\nمثال:\n${usedPrefix + command} https://www.instagram.com/reel/XXXXXX/`);
    }

    await m.react('🔍');
    try {
        const result = await apiPost('media/parse', { origin: 'source', link });
        if (result?.status !== 1 || !result?.data) {
            throw new Error(result?.msg || result?.status_code || 'تعذر تحليل الرابط');
        }

        const options = buildOptions(result.data, usedPrefix);
        if (!options.length) throw new Error('لم تُرجع الخدمة أي جودة قابلة للتحميل');

        let mediaMessage = null;
        if (result.data.thumbnail) {
            try {
                mediaMessage = await prepareWAMessageMedia(
                    { image: { url: result.data.thumbnail } },
                    { upload: conn.waUploadToServer }
                );
            } catch (error) {
                console.warn('[ig-downloader] thumbnail skipped:', error.message);
            }
        }

        const title = safeText(result.data.title, 'Instagram Media').slice(0, 80);
        const interactiveMessage = {
            body: {
                text: `*📸 Instagram Downloader*\n\n📌 *العنوان:* ${title}\n🔗 *الرابط:* ${link}\n\nاختر الجودة أو نوع الملف المطلوب:`
            },
            footer: { text: '✦ ARAB TOP DEV ✦' },
            header: mediaMessage ? {
                hasMediaAttachment: true,
                imageMessage: mediaMessage.imageMessage
            } : { hasMediaAttachment: false },
            nativeFlowMessage: {
                buttons: [{
                    name: 'single_select',
                    buttonParamsJson: JSON.stringify({
                        title: '📥 خيارات التحميل',
                        sections: [{ title: 'الجودات المتاحة', rows: options }]
                    })
                }],
                messageParamsJson: JSON.stringify({
                    bottom_sheet: {
                        list_title: 'اختر الجودة',
                        button_title: 'تحميل'
                    }
                })
            }
        };

        const msg = generateWAMessageFromContent(m.chat, {
            viewOnceMessage: {
                message: {
                    interactiveMessage: proto.Message.InteractiveMessage.fromObject(interactiveMessage)
                }
            }
        }, { userJid: conn.user.jid, quoted: m });

        await conn.relayMessage(m.chat, msg.message, { messageId: msg.key.id });
        await m.react('📥');
    } catch (error) {
        console.error('[ig-downloader]', error);
        await m.react('❌');
        await m.reply(`❌ تعذر جلب الميديا: ${error.message || 'خدمة التحليل غير متاحة حالياً.'}`);
    }
};

handler.help = ['انستا'];
handler.tags = ['downloader'];
handler.command = /^(انستا|ig|dl_ig_media)$/i;

export default handler;

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

Admin · قبل ساعة واحدة

هههلاااااا

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