/*** @ Base: https://www.instagram.com/ @ Author: Shannz @ Note: Instagram downloader with complete metadata. ***/ import axios from 'axios'; import * as cheerio from 'cheerio'; import { XMLParser } from 'fast-xml-parser'; export async function instagram(url) { if (!url) return { status: false, error: 'URL tidak valid atau kosong.' }; try { console.log(`Please Wait...`); const response = await axios.get(url, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'cache-control': 'max-age=0', 'dpr': '2', 'viewport-width': '980', 'sec-ch-ua': '"Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"', 'sec-ch-ua-mobile': '?1', 'sec-ch-ua-platform': '"Android"', 'sec-ch-ua-platform-version': '"15.0.0"', 'sec-ch-ua-model': '"25028RN03A"', 'sec-ch-ua-full-version-list': '"Chromium";v="136.0.7103.125", "Google Chrome";v="136.0.7103.125", "Not.A/Brand";v="99.0.0.0"', 'sec-ch-prefers-color-scheme': 'light', 'dnt': '1', 'upgrade-insecure-requests': '1', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'navigate', 'sec-fetch-user': '?1', 'sec-fetch-dest': 'document', 'accept-language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7', 'priority': 'u=0, i' }, timeout: 10000 }); const $ = cheerio.load(response.data); let scriptJson = null; $('script[type="application/json"]').each((_, el) => { const content = $(el).html(); if (content && content.includes('xdt_api__v1__media__shortcode__web_info')) { try { scriptJson = JSON.parse(content); } catch (parseError) { console.error('JSON Parse Error:', parseError.message); } } }); if (!scriptJson) throw new Error('Data script tidak ditemukan (Mungkin IP Blocked atau bukan Reels).'); const item = scriptJson.require?.[0]?.[3]?.[0]?.__bbox?.require?.[0]?.[3]?.[1]?.__bbox?.result?.data?.xdt_api__v1__media__shortcode__web_info?.items?.[0]; if (!item) throw new Error('Struct item tidak ditemukan dalam JSON.'); const dashXml = item.video_dash_manifest; if (!dashXml) throw new Error('Manifest XML tidak ditemukan.'); const parser = new XMLParser({ ignoreAttributes: false }); let manifest; try { manifest = parser.parse(dashXml); } catch (xmlError) { throw new Error(`Gagal parsing DASH manifest: ${xmlError.message}`); } const period = manifest.MPD?.Period; if (!period) throw new Error('Tag Period tidak ditemukan di XML.'); const adaptationSets = Array.isArray(period.AdaptationSet) ? period.AdaptationSet : [period.AdaptationSet]; let videoTracks = []; let audioTracks = []; adaptationSets.forEach((set) => { if (!set) return; const isVideo = set['@_contentType'] === 'video'; const isAudio = set['@_contentType'] === 'audio'; const representations = Array.isArray(set.Representation) ? set.Representation : [set.Representation]; representations.forEach((rep) => { if (!rep) return; const track = { url: rep.BaseURL, bandwidth: parseInt(rep['@_bandwidth']) || 0, codecs: rep['@_codecs'] || '', mimeType: rep['@_mimeType'] || '', }; if (isVideo) { videoTracks.push({ ...track, resolution: `${rep['@_width']}x${rep['@_height']}`, qualityLabel: rep['@_FBQualityLabel'] || '' }); } else if (isAudio) { audioTracks.push(track); } }); }); videoTracks.sort((a, b) => b.bandwidth - a.bandwidth); const finalResult = { metadata: { id: item.id, code: item.code, caption: item.caption?.text || '', createTime: new Date(item.taken_at * 1000).toLocaleString(), }, author: { id: item.user?.pk, username: item.user?.username || 'N/A', fullName: item.user?.full_name || '', profilePic: item.user?.hd_profile_pic_url_info?.url || '', verified: item.user?.is_verified }, media: { thumbnails: (item.image_versions2?.candidates || []).map(img => ({ url: img.url, resolution: `${img.width}x${img.height}` })), videos: videoTracks, audios: audioTracks } }; return { status: true, result: finalResult }; } catch (error) { console.error('Error Main Process:', error.message); return { status: false, error: error.message }; } }