Back to Home
Gistify Snippet
Public
Scraper snapsave
Scraper snapsave
#github-gist#javascript#gist:d406a12addf8435798eb826a5867e2a4#gistsync:2026-09-02T12:40:41Z
0
Rawsnapsave.jsjavascript
220 lines| 1 | |
| 2 | |
| 3 | import * as __ns_780 from 'node-fetch' |
| 4 | const fetch = __ns_780.default |
| 5 | import * as __ns_781 from 'node:crypto' |
| 6 | const crypto = __ns_781.default |
| 7 | import * as __ns_782 from 'node:url' |
| 8 | const pathToFileURL = __ns_782.pathToFileURL |
| 9 | |
| 10 | const BASE = "https://snapsave.app"; |
| 11 | const UA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Mobile Safari/537.36"; |
| 12 | |
| 13 | function randomGa() { |
| 14 | return `GA1.1.${Math.floor(Math.random() * 2_000_000_000)}.${Math.floor(Date.now() / 1000)}`; |
| 15 | } |
| 16 | |
| 17 | function randomPhpSession() { |
| 18 | return crypto.randomBytes(13).toString("hex").slice(0, 26); |
| 19 | } |
| 20 | |
| 21 | function parseSetCookie(headers) { |
| 22 | const cookies = []; |
| 23 | const raw = headers.get("set-cookie"); |
| 24 | if (raw) { |
| 25 | cookies.push(...raw.split(/,(?=[^;,]+=)/).map((v) => v.split(";")[0].trim())); |
| 26 | } |
| 27 | return cookies; |
| 28 | } |
| 29 | |
| 30 | function mergeCookies(...lists) { |
| 31 | const map = new Map(); |
| 32 | for (const list of lists) { |
| 33 | for (const item of list) { |
| 34 | const [key] = item.split("="); |
| 35 | if (key) map.set(key.trim(), item.trim()); |
| 36 | } |
| 37 | } |
| 38 | return [...map.values()].join("; "); |
| 39 | } |
| 40 | |
| 41 | function defaultCookies() { |
| 42 | const now = Math.floor(Date.now() / 1000); |
| 43 | return [ |
| 44 | `_ga=${randomGa()}`, |
| 45 | `PHPSESSID=${randomPhpSession()}`, |
| 46 | "__jscuActive=true", |
| 47 | `_ga_WNPZGVDWE9=GS2.1.s${now}$o1$g0$t${now}$j60$l0$h0`, |
| 48 | ]; |
| 49 | } |
| 50 | |
| 51 | function baseHeaders(cookie = "") { |
| 52 | return { |
| 53 | "user-agent": UA, |
| 54 | "sec-ch-ua": `"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"`, |
| 55 | "sec-ch-ua-mobile": "?1", |
| 56 | "sec-ch-ua-platform": `"Android"`, |
| 57 | "accept-language": "id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7", |
| 58 | ...(cookie ? { cookie } : {}), |
| 59 | }; |
| 60 | } |
| 61 | |
| 62 | async function initCookie() { |
| 63 | const seed = defaultCookies().join("; "); |
| 64 | try { |
| 65 | const res = await fetch(`${BASE}/id/download-video-instagram`, { |
| 66 | method: "GET", |
| 67 | headers: { |
| 68 | ...baseHeaders(seed), |
| 69 | accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8", |
| 70 | "upgrade-insecure-requests": "1", |
| 71 | }, |
| 72 | }); |
| 73 | const setCookies = parseSetCookie(res.headers); |
| 74 | return mergeCookies(defaultCookies(), setCookies); |
| 75 | } catch { |
| 76 | return seed; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | function convertBase(value, fromBase, toBase) { |
| 81 | const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/".split(""); |
| 82 | const fromChars = chars.slice(0, fromBase); |
| 83 | const toChars = chars.slice(0, toBase); |
| 84 | let number = value.split("").reverse().reduce((acc, char, index) => { |
| 85 | const pos = fromChars.indexOf(char); |
| 86 | if (pos !== -1) return acc + pos * Math.pow(fromBase, index); |
| 87 | return acc; |
| 88 | }, 0); |
| 89 | let out = ""; |
| 90 | while (number > 0) { |
| 91 | out = toChars[number % toBase] + out; |
| 92 | number = (number - (number % toBase)) / toBase; |
| 93 | } |
| 94 | return out || "0"; |
| 95 | } |
| 96 | |
| 97 | function decodeSnapSaveEval(html) { |
| 98 | const match = html.match(/eval\(function\(h,u,n,t,e,r\)[\s\S]*?\}\("([^ "]+)",(\d+),"([^ "]+)",(\d+),(\d+),(\d+)\)\)/); |
| 99 | if (!match) return html; |
| 100 | const h = match[1], n = match[3], t = Number(match[4]), e = Number(match[5]); |
| 101 | const delimiter = n[e]; |
| 102 | let result = ""; |
| 103 | for (let i = 0; i < h.length; i++) { |
| 104 | let chunk = ""; |
| 105 | while (i < h.length && h[i] !== delimiter) { chunk += h[i]; i++; } |
| 106 | for (let j = 0; j < n.length; j++) chunk = chunk.replaceAll(n[j], String(j)); |
| 107 | result += String.fromCharCode(Number(convertBase(chunk, e, 10)) - t); |
| 108 | } |
| 109 | return decodeURIComponent(escape(result)); |
| 110 | } |
| 111 | |
| 112 | function extractResults(decoded) { |
| 113 | const text = decoded.replaceAll('\\"', '"').replaceAll("\\/", "/").replaceAll("&", "&").replaceAll("\\n", "").replaceAll("\\t", "").trim(); |
| 114 | const results = []; |
| 115 | const hrefRegex = /href="([^ "]+)"/g; |
| 116 | let match; |
| 117 | while ((match = hrefRegex.exec(text))) { |
| 118 | const url = match[1]; |
| 119 | if (!url.includes("rapidcdn.app") && !url.includes("cdninstagram.com")) continue; |
| 120 | let type = "image"; |
| 121 | let filename = ""; |
| 122 | |
| 123 | try { |
| 124 | if (url.includes("token=")) { |
| 125 | const token = url.split("token=")[1]?.split("&")[0]; |
| 126 | if (token) { |
| 127 | const payloadStr = Buffer.from(token.split(".")[1] || "", "base64").toString(); |
| 128 | const payload = JSON.parse(payloadStr); |
| 129 | filename = payload.filename || ""; |
| 130 | } |
| 131 | } |
| 132 | } catch {} |
| 133 | |
| 134 | const checkStr = (filename + " " + url).toLowerCase(); |
| 135 | if (/\.mp4|video/i.test(checkStr)) { |
| 136 | type = "video"; |
| 137 | } else { |
| 138 | type = "image"; |
| 139 | } |
| 140 | |
| 141 | results.push({ type, url, filename }); |
| 142 | } |
| 143 | const unique = []; |
| 144 | const seen = new Set(); |
| 145 | for (const item of results) { |
| 146 | if (seen.has(item.url)) continue; |
| 147 | seen.add(item.url); |
| 148 | unique.push(item); |
| 149 | } |
| 150 | return unique; |
| 151 | } |
| 152 | |
| 153 | async function snapsave(url) { |
| 154 | try { |
| 155 | const cookie = await initCookie(); |
| 156 | const body = new URLSearchParams(); |
| 157 | body.append("url", url); |
| 158 | const res = await fetch(`${BASE}/id/action.php?lang=id`, { |
| 159 | method: "POST", |
| 160 | headers: { |
| 161 | ...baseHeaders(cookie), |
| 162 | "content-type": "application/x-www-form-urlencoded", |
| 163 | accept: "*/*", |
| 164 | origin: BASE, |
| 165 | referer: `${BASE}/id/download-video-instagram`, |
| 166 | }, |
| 167 | body: body.toString(), |
| 168 | }); |
| 169 | const raw = await res.text(); |
| 170 | const decoded = decodeSnapSaveEval(raw); |
| 171 | const result = extractResults(decoded); |
| 172 | return { |
| 173 | status: res.ok && result.length > 0, |
| 174 | result, |
| 175 | }; |
| 176 | } catch (e) { |
| 177 | return { status: false, error: e.message }; |
| 178 | } |
| 179 | } |
| 180 | if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { |
| 181 | const __exports = { snapsave: snapsave } |
| 182 | const __fns = Object.fromEntries(Object.entries(__exports).filter(([, v]) => typeof v === 'function')) |
| 183 | const __names = Object.keys(__fns) |
| 184 | if (__names.length === 0) { |
| 185 | console.log('Tidak ada fungsi yang bisa di-demo. Import modul ini dari kode lain.') |
| 186 | } else { |
| 187 | const __search = __names.find((n) => /search|cari/i.test(n)) |
| 188 | const __name = __search || __names[0] |
| 189 | const __fn = __fns[__name] |
| 190 | const __isClass = /^class\s/.test(Function.prototype.toString.call(__fn)) |
| 191 | const __defaultArgs = (() => { |
| 192 | const n = __name.toLowerCase() |
| 193 | if (/emoji/.test(n)) return [{ emoji: '😀😃' }] |
| 194 | if (/textpro|generate.*text|effect/.test(n)) return ['neon', 'Hello'] |
| 195 | if (/image|wallpaper|search|query|anime|movie|manga|news|lyrics|wiki|quote|stalk|detail/.test(n)) return ['naruto'] |
| 196 | if (/download|youtube|video|audio|music|spotify|tiktok|instagram|facebook|twitter|reels|terabox|media/.test(n)) return ['https://www.youtube.com/watch?v=dQw4w9WgXcQ'] |
| 197 | if (/dork/.test(n)) return ['example.com', 'documents'] |
| 198 | if (/tts|speech|prompt|chat|ask|translate/.test(n)) return ['Hello world'] |
| 199 | if (/parse|format|normalize|list|features/.test(n)) return [] |
| 200 | return ['test'] |
| 201 | })() |
| 202 | let __args = __defaultArgs |
| 203 | if (process.argv.length > 2) __args = process.argv.slice(2).map((a) => { try { return JSON.parse(a) } catch { return a } }) |
| 204 | if (__args.length === 0 && !__search && !__isClass && __fn.length > 0) { |
| 205 | console.log('Fungsi: ' + __names.join(', ')) |
| 206 | console.log('Contoh: node ' + "snapsave.js" + ' ' + __name + ' <arg>') |
| 207 | } else { |
| 208 | ;(async () => { |
| 209 | try { |
| 210 | const r = __isClass ? new __fn(...__args) : await __fn(...__args) |
| 211 | console.log(JSON.stringify(r, null, 2)) |
| 212 | } catch (e) { |
| 213 | console.error('Error: ' + (e && e.message ? e.message : e)) |
| 214 | process.exitCode = 1 |
| 215 | } |
| 216 | })() |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
Discussion & Comments0
No comments yet — be the first to leave feedback or start a code discussion.
Sign in with your GitHub account to write comments and join the discussion.