Back to Home
Gistify Snippet
kyiov
Sep 3·1 file(s)
Public

Scraper snapsave

Scraper snapsave

#github-gist#javascript#gist:d406a12addf8435798eb826a5867e2a4#gistsync:2026-09-02T12:40:41Z
0
Raw
snapsave.jsjavascript
220 lines
1
2
3import * as __ns_780 from 'node-fetch'
4const fetch = __ns_780.default
5import * as __ns_781 from 'node:crypto'
6const crypto = __ns_781.default
7import * as __ns_782 from 'node:url'
8const pathToFileURL = __ns_782.pathToFileURL
9
10const BASE = "https://snapsave.app";
11const UA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Mobile Safari/537.36";
12
13function randomGa() {
14 return `GA1.1.${Math.floor(Math.random() * 2_000_000_000)}.${Math.floor(Date.now() / 1000)}`;
15}
16
17function randomPhpSession() {
18 return crypto.randomBytes(13).toString("hex").slice(0, 26);
19}
20
21function 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
30function 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
41function 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
51function 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
62async 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
80function 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
97function 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
112function extractResults(decoded) {
113 const text = decoded.replaceAll('\\"', '"').replaceAll("\\/", "/").replaceAll("&amp;", "&").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
153async 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}
180if (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.