javascript oleh fazzcode 14 Sep 2026, 11.05

Instagram Downloader

Udah Gitu Aja

#!/usr/bin/env node
/**
 * Powered FazzCodeID
 * Base Url : 9xbuddy.site
 * 
 *   
 */

import fs from "node:fs";
import path from "node:path";
import https from "node:https";
import http from "node:http";
import crypto from "node:crypto";
import { pathToFileURL } from "node:url";

const CONFIG = {
  SITE: "https://9xbuddy.site",
  LOCALE: process.env.LOCALE || "id",
  TIMEOUT_MS: 60_000,
  DOWNLOAD_TIMEOUT_MS: 180_000,
  UA: "Mozilla/5.0 (Android 15; Mobile; rv:155.0) Gecko/155.0 Firefox/155.0",
  SIG_SUFFIX: "E",
  DECODE_PREFIX: "SORRY_MATE",  
};

const C = { reset: "\x1b[0m", dim: "\x1b[2m", green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m" };
const log = {
  info: (t, m) => console.error(`${C.dim}[${t}]${C.reset} ${m}`),
  ok:   (t, m) => console.error(`${C.green}[${t}]${C.reset} ${m}`),
  warn: (t, m) => console.error(`${C.yellow}[${t}]${C.reset} ${m}`),
  err:  (t, m) => console.error(`${C.red}[${t}]${C.reset} ${m}`),
  hit:  (t, m) => console.error(`${C.cyan}[${t}]${C.reset} ${m}`),
};

class N {
  static decode64(e) {
    e = e.replace(/\s/g, "");
    if (!/^[a-z0-9+/]+\={0,2}$/i.test(e) || e.length % 4 > 0) return null;
    try { return Buffer.from(e, "base64").toString("binary"); } catch { return null; }
  }
  static encode64(e) {
    const buf = Buffer.alloc(e.length);
    for (let i = 0; i < e.length; i++) buf[i] = e.charCodeAt(i) & 0xff;
    return buf.toString("base64");
  }
  static encrypt(pt, key) {
    if (!key || key.length === 0) return null;
    let out = "";
    for (let r = 0; r < pt.length; r++) {
      const p = pt.charCodeAt(r);
      const ki = (r % key.length) - 1;
      const kc = key.charCodeAt(ki < 0 ? key.length - 1 : ki);
      out += String.fromCharCode((p + kc) & 0xff);
    }
    return this.encode64(out);
  }
  static decrypt(ct, key) {
    const d = this.decode64(ct);
    if (!d) return null;
    let out = "";
    for (let r = 0; r < d.length; r++) {
      const c = d.charCodeAt(r);
      const ki = (r % key.length) - 1;
      const kc = key.charCodeAt(ki < 0 ? key.length - 1 : ki);
      out += String.fromCharCode((c - kc) & 0xff);
    }
    return out;
  }
  static hex2bin(hex) {
    const out = [];
    for (let i = 0; i < hex.length; i += 2) {
      const hi = parseInt(hex[i], 16);
      const lo = parseInt(hex[i + 1], 16);
      if (Number.isNaN(hi) || Number.isNaN(lo)) return null;
      out.push((hi << 4) | lo);
    }
    return String.fromCharCode(...out);
  }
}

const SECRET = "SORRY_MATE_IM_NOT_GONNA_TELL_YOU";

const cookieJar = new Map();
function captureCookies(headers) {
  for (const c of headers["set-cookie"] || []) {
    const [pair] = c.split(";");
    const eq = pair.indexOf("=");
    if (eq > 0) cookieJar.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim());
  }
}
function cookieHeader() {
  return [...cookieJar.entries()].map(([k, v]) => `${k}=${v}`).join("; ");
}

function request(url, opts = {}) {
  const { method = "GET", headers = {}, body = null, timeout = CONFIG.TIMEOUT_MS, redirects = 5 } = opts;
  return new Promise((resolve, reject) => {
    const parsed = new URL(url);
    const lib = parsed.protocol === "https:" ? https : http;
    const h = { "User-Agent": CONFIG.UA, "Accept-Language": "en-US,en;q=0.9,id;q=0.8", ...headers };
    const cookie = cookieHeader();
    if (cookie) h.Cookie = cookie;
    const req = lib.request(
      { method, hostname: parsed.hostname, port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
        path: parsed.pathname + parsed.search, headers: h },
      (res) => {
        captureCookies(res.headers);
        if (redirects > 0 && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
          res.resume();
          return request(new URL(res.headers.location, url).toString(), { ...opts, redirects: redirects - 1 }).then(resolve, reject);
        }
        const chunks = [];
        res.on("data", (c) => chunks.push(c));
        res.on("end", () => resolve({ status: res.statusCode, headers: res.headers, body: Buffer.concat(chunks).toString("utf-8"), buffer: Buffer.concat(chunks) }));
      }
    );
    req.on("error", reject);
    req.setTimeout(timeout, () => req.destroy(new Error(`Timeout ${timeout}ms`)));
    if (body) req.write(body);
    req.end();
  });
}

function extractInit(html) {
  const start = html.indexOf("window.__INIT__");
  if (start === -1) throw new Error("__INIT__ tidak ditemukan");
  const eq = html.indexOf("=", start);
  let i = eq + 1;
  while (i < html.length && /\s/.test(html[i])) i++;
  if (html[i] !== "{") throw new Error("Format __INIT__ salah");
  let depth = 0, inStr = false, strChar = "", esc = false;
  const startJson = i;
  for (; i < html.length; i++) {
    const ch = html[i];
    if (esc) { esc = false; continue; }
    if (ch === "\\") { esc = true; continue; }
    if (inStr) { if (ch === strChar) inStr = false; continue; }
    if (ch === '"' || ch === "'") { inStr = true; strChar = ch; continue; }
    if (ch === "{") depth++;
    else if (ch === "}") { depth--; if (depth === 0) return JSON.parse(html.slice(startJson, i + 1)); }
  }
  throw new Error("Parse __INIT__ gagal");
}

function parseInstagramUrl(rawUrl) {
  const clean = rawUrl.replace(/\\([?=&])/g, "$1").trim();
  const m = clean.match(/instagram\.com\/(?:reel|reels|p|tv)\/([A-Za-z0-9_-]+)/);
  return m ? { cleanUrl: clean, shortcode: m[1] } : null;
}

function generateAuthToken(init, cssHash) {
  const cssRev = cssHash.split("").reverse().join("");
  const uaRev = (init.ua || "").split("").reverse().join("").substr(0, 10);
  const hostname = new URL(CONFIG.SITE).hostname;
  const appVer = init.appVersion;
  const c = `xbuddy123sudo-${appVer}`;
  const payload = hostname + cssRev + uaRev + SECRET + c + appVer;
  return { authToken: N.encrypt(payload, cssRev), cssRev, hostname, appVersion: appVer };
}

async function fetchAccessToken(init, authToken, hostname) {
  const res = await request(`${init.apiBase}/token`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json; charset=UTF-8",
      Accept: "application/json, text/plain, */*",
      "X-Requested-With": "xmlhttprequest",
      "x-auth-token": authToken,
      "x-requested-domain": hostname,
      Origin: CONFIG.SITE, Referer: `${CONFIG.SITE}/`,
    },
    body: "{}",
  });
  const data = JSON.parse(res.body);
  if (!data.access_token) throw new Error(`Token gagal: ${res.body.slice(0, 150)}`);
  return data.access_token;
}

function generateSig(urlEncoded, authToken) {
  return N.encrypt(urlEncoded, authToken + CONFIG.SIG_SUFFIX);
}
async function callExtract(init, authToken, accessToken, url, opts = {}) {
  const hostname = new URL(CONFIG.SITE).hostname;
  const urlEncoded = encodeURIComponent(url);
  const sig = generateSig(urlEncoded, authToken);

  const body = {
    url: urlEncoded,
    _sig: sig,
    searchEngine: opts.searchEngine ?? "yt",
    skipCache: opts.skipCache ?? false,
    extractionId: opts.extractionId ?? crypto.randomUUID(),
  };

  const res = await request(`${init.apiBase}/extract`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json; charset=UTF-8",
      Accept: "application/json, text/plain, */*",
      "X-Requested-With": "xmlhttprequest",
      "x-auth-token": authToken,
      "x-access-token": accessToken,
      "x-requested-domain": hostname,
      Origin: CONFIG.SITE, Referer: `${CONFIG.SITE}/`,
    },
    body: JSON.stringify(body),
  });

  let parsed = null;
  try { parsed = JSON.parse(res.body); } catch {}
  return { status: res.status, data: parsed, raw: res.body };
}

function decodeUrl(hexUrl, cssHash, token, hostname) {
  if (!hexUrl || !token) return null;


  if (/^https?:\/\//i.test(hexUrl)) return hexUrl;
  const binStr = N.hex2bin(hexUrl);
  if (!binStr) return null;
  const reversed = binStr.split("").reverse().join("");
  const prefix = CONFIG.DECODE_PREFIX;
  const hostLen = String(hostname.length);
  const key = prefix + hostLen + cssHash + token;

  log.info("DECODE", `key_len=${key.length} prefix=${prefix} hostLen=${hostLen} cssHash=${cssHash.slice(0, 8)}...`);
  const result = N.decrypt(reversed, key);

  if (typeof result !== "string") return null;
  if (!/^[\x20-\x7e]+$/.test(result)) return null;

  return result;
}
export async function scrape(rawUrl, options = {}) {
  const parsed = parseInstagramUrl(rawUrl);
  if (!parsed) return { success: false, error: "URL Instagram tidak valid", formats: [] };
  const { cleanUrl } = parsed;

  const result = {
    success: false, input_url: rawUrl, clean_url: cleanUrl,
    title: null, thumbnail: null, uploader: null,
    formats: [], errors: [],
  };

  try {
    const pageUrl = `${CONFIG.SITE}/${CONFIG.LOCALE}/process?url=${encodeURIComponent(cleanUrl)}`;
    log.info("GET", pageUrl);
    const pageRes = await request(pageUrl, {
      headers: {
        Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Upgrade-Insecure-Requests": "1",
      },
    });
    if (pageRes.status !== 200) throw new Error(`Page HTTP ${pageRes.status}`);

    const init = extractInit(pageRes.body);
    const cssMatch = pageRes.body.match(/\/build\/(?:assets\/)?main\.([^"']+?)\.css/);
    if (!cssMatch) throw new Error("CSS hash tidak ditemukan");
    const cssHash = cssMatch[1];
    log.ok("INIT", `appVer=${init.appVersion} cssHash=${cssHash}`);

    const { authToken, hostname } = generateAuthToken(init, cssHash);
    const accessToken = await fetchAccessToken(init, authToken, hostname);
    log.ok("TOKEN", `auth=${authToken.length}c access=${accessToken.length}c`);

    const extraction = await callExtract(init, authToken, accessToken, cleanUrl, {
      searchEngine: options.searchEngine ?? "yt",
    });

    if (!extraction.data || extraction.data.status !== "1" || !extraction.data.response) {
      const msg = extraction.data?.message || "unknown";
      result.errors.push({ stage: "extract", message: msg });
      log.err("EXTRACT", msg);
      return result;
    }

    const resp = extraction.data.response;
    result.title = resp.title || null;
    result.thumbnail = resp.thumbnail || null;
    result.uploader = resp.uploader || null;

    const responseToken = resp.token || accessToken;
    log.info("TOKEN", `response.token=${responseToken.slice(0, 20)}... (len=${responseToken.length})`);
    for (const f of resp.formats || []) {
      let url = null;
      try {
        url = decodeUrl(f.url, cssHash, responseToken, hostname);
      } catch (e) {
        log.warn("DECODE", `Format ${f.quality}: ${e.message}`);
      }

      result.formats.push({
        quality: f.quality || null,
        type: f.type || null,
        ext: f.ext || null,
        width: f.width || null,
        height: f.height || null,
        size: f.size || null,
        url,
      });
    }

    result.success = result.formats.some((f) => f.url);
    log.hit("DONE", `${result.formats.filter((f) => f.url).length}/${result.formats.length} URL decoded`);
  } catch (err) {
    result.errors.push({ stage: "fatal", message: err.message });
    log.err("ERROR", err.message);
  }

  return result;
}
export async function download(url, outPath) {
  const res = await request(url, {
    timeout: CONFIG.DOWNLOAD_TIMEOUT_MS,
    headers: { Referer: "https://www.instagram.com/" },
  });
  if (res.status !== 200) throw new Error(`HTTP ${res.status}`);
  fs.mkdirSync(path.dirname(outPath), { recursive: true });
  fs.writeFileSync(outPath, res.buffer);
  return { path: outPath, size: res.buffer.length };
}

async function main() {
  const args = process.argv.slice(2);
  if (args.length === 0) {
    console.error("Usage: node ig.js <instagram-url> [-d] [-o dir]");
    process.exit(1);
  }
  const url = args.find((a) => !a.startsWith("-"));
  const flags = {
    download: args.includes("-d") || args.includes("--download"),
    outDir: args.includes("-o") ? args[args.indexOf("-o") + 1] : "./downloads",
  };
  const result = await scrape(url);
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");

  if (result.success && flags.download) {
    console.error("");
    const shortcode = (url.match(/\/(?:reel|reels|p|tv)\/([A-Za-z0-9_-]+)/) || [])[1] || "ig";
    for (const f of result.formats) {
      if (!f.url) continue;
      const suffix = (f.quality || "file").replace(/[^a-z0-9_]/gi, "_");
      const filename = `${shortcode}_${suffix}.${f.ext || "mp4"}`;
      const outPath = path.join(flags.outDir, filename);
      try {
        const { size } = await download(f.url, outPath);
        log.ok("DL", `${filename} (${(size / 1024).toFixed(1)} KB)`);
      } catch (e) {
        log.err("DL", `${filename}: ${e.message}`);
      }
    }
  }

  process.exit(result.success ? 0 : 1);
}

const isMain = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
if (isMain) main().catch((e) => { console.error("Fatal:", e); process.exit(1); });
Discussion

Thread

Belum ada komentarJadilah yang pertama membuka diskusi.