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

Scraper iloveimg

Scraper iloveimg

#github-gist#javascript#gist:39401894229df773b0d21aff7bc316dd#gistsync:2026-09-02T12:40:34Z
1
Raw
iloveimg.jsjavascript
373 lines
1
2
3import * as __ns_613 from 'axios'
4const axios = __ns_613.default
5import * as __ns_614 from 'cheerio'
6const cheerio = __ns_614
7import * as __ns_615 from 'crypto'
8const crypto = __ns_615.default
9import * as __ns_616 from 'form-data'
10const FormData = __ns_616.default
11import * as __ns_617 from 'fs'
12const fs = __ns_617.default
13import * as __ns_618 from 'fs/promises'
14const fsp = __ns_618.default
15import * as __ns_619 from 'node:url'
16const pathToFileURL = __ns_619.pathToFileURL
17import * as __ns_620 from 'os'
18const os = __ns_620.default
19import * as __ns_621 from 'path'
20const path = __ns_621.default
21
22const TOOL = "compressimage";
23const UA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Mobile Safari/537.36";
24const SERVERS = [
25 "api1g", "api2g", "api3g", "api8g", "api9g", "api10g", "api11g",
26 "api12g", "api13g", "api14g", "api15g", "api16g", "api17g",
27 "api18g", "api19g", "api20g", "api21g", "api22g", "api24g", "api25g",
28 "api1", "api2", "api3", "api4", "api5", "api6", "api7", "api8",
29 "api9", "api10", "api11", "api12", "api13", "api14", "api15",
30 "api16", "api17", "api18", "api19", "api20", "api21", "api22",
31 "api23", "api24", "api25", "api26", "api27", "api28", "api29",
32 "api30", "api31", "api32", "api33", "api34", "api35", "api36",
33 "api37", "api38", "api39", "api40"
34];
35
36function randomTask(length = 120) {
37 const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
38 let result = "";
39 while (result.length < length) {
40 const bytes = crypto.randomBytes(length);
41 for (const byte of bytes) {
42 if (result.length >= length) break;
43 result += chars[byte % chars.length];
44 }
45 }
46 return result;
47}
48
49function shuffle(array) {
50 return [...array].sort(() => Math.random() - 0.5);
51}
52
53function contentType(file) {
54 const ext = path.extname(file).toLowerCase();
55 if (ext === ".png") return "image/png";
56 if (ext === ".webp") return "image/webp";
57 if (ext === ".gif") return "image/gif";
58 if (ext === ".bmp") return "image/bmp";
59 if (ext === ".tif" || ext === ".tiff") return "image/tiff";
60 return "image/jpeg";
61}
62
63async function getToken() {
64 const res = await axios.get("https://www.iloveimg.com/compress-image", {
65 headers: {
66 "user-agent": UA,
67 accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
68 "accept-language": "id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7"
69 },
70 timeout: 120000,
71 validateStatus: () => true
72 });
73 if (res.status !== 200) throw new Error(`Gagal membuka halaman token: HTTP ${res.status}`);
74 const $ = cheerio.load(res.data);
75 const script = $("script").filter((_, el) => String($(el).html() || "").includes("ilovepdfConfig =")).html();
76 if (!script) throw new Error("Config script tidak ditemukan");
77 const jsonText = script.split("ilovepdfConfig = ")[1]?.split(";")[0];
78 if (!jsonText) throw new Error("Config JSON tidak ditemukan");
79 const json = JSON.parse(jsonText);
80 const csrf = $("meta[name='csrf-token']").attr("content");
81 if (!json.token || !csrf) throw new Error("Token atau CSRF tidak ditemukan");
82 return { token: json.token, csrf };
83}
84
85async function uploadImage(server, headers, input, task) {
86 const form = new FormData();
87 form.append("name", path.basename(input));
88 form.append("chunk", "0");
89 form.append("chunks", "1");
90 form.append("task", task);
91 form.append("preview", "1");
92 form.append("file", fs.createReadStream(input), {
93 filename: path.basename(input),
94 contentType: contentType(input)
95 });
96 const res = await axios.post(`https://${server}.iloveimg.com/v1/upload`, form, {
97 headers: { ...headers, ...form.getHeaders() },
98 timeout: 180000,
99 maxContentLength: Infinity,
100 maxBodyLength: Infinity,
101 validateStatus: () => true
102 });
103 if (res.status !== 200 || !res.data?.server_filename) throw new Error(`Upload gagal: HTTP ${res.status}`);
104 return { filename: res.data.filename || path.basename(input), server_filename: res.data.server_filename };
105}
106
107async function processCompress(server, headers, task, file) {
108 const payload = { task, tool: TOOL, files: [{ server_filename: file.server_filename, filename: file.filename }] };
109 const res = await axios.post(`https://${server}.iloveimg.com/v1/process`, payload, {
110 headers: { ...headers, "content-type": "application/json" },
111 timeout: 180000,
112 maxContentLength: Infinity,
113 maxBodyLength: Infinity,
114 validateStatus: () => true
115 });
116 if (res.status !== 200) throw new Error(`Process gagal: HTTP ${res.status}`);
117 return res.data;
118}
119
120async function downloadResult(server, headers, task) {
121 const res = await axios.get(`https://${server}.iloveimg.com/v1/download/${task}`, {
122 headers,
123 responseType: "arraybuffer",
124 timeout: 180000,
125 maxContentLength: Infinity,
126 maxBodyLength: Infinity,
127 validateStatus: () => true
128 });
129 if (res.status !== 200 || !res.data) throw new Error(`Download gagal: HTTP ${res.status}`);
130 return Buffer.from(res.data);
131}
132
133async function compressImage(buffer, ext = 'jpg') {
134 const tempFile = path.join(os.tmpdir(), `iloveimg-${Date.now()}.${ext}`);
135 await fsp.writeFile(tempFile, buffer);
136
137 try {
138 const { token, csrf } = await getToken();
139 const errors = [];
140 for (const server of shuffle(SERVERS)) {
141 const task = randomTask();
142 const headers = {
143 authorization: `Bearer ${token}`,
144 origin: "https://www.iloveimg.com",
145 referer: "https://www.iloveimg.com/compress-image",
146 cookie: `_csrf=${csrf}`,
147 "user-agent": UA,
148 accept: "application/json, text/plain, */*"
149 };
150 try {
151 const uploaded = await uploadImage(server, headers, tempFile, task);
152 await processCompress(server, headers, task, uploaded);
153 const resultBuffer = await downloadResult(server, headers, task);
154
155 const inputSize = buffer.length;
156 const outputSize = resultBuffer.length;
157
158 await fsp.unlink(tempFile);
159 return {
160 Status: true,
161 Buffer: resultBuffer,
162 InputSize: inputSize,
163 OutputSize: outputSize,
164 SavedSize: Math.max(0, inputSize - outputSize)
165 };
166 } catch (err) {
167 errors.push(err.message);
168 }
169 }
170 throw new Error(errors.slice(0, 5).join(" | "));
171 } catch (e) {
172 if (fs.existsSync(tempFile)) await fsp.unlink(tempFile);
173 return { Status: false, Error: e.message };
174 }
175}
176
177async function getUpscaleAuthToken() {
178 const pageUrl = 'https://www.iloveimg.com/upscale-image';
179 const res = await axios.get(pageUrl, {
180 headers: {
181 'User-Agent': UA,
182 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
183 'Accept-Language': 'en-US,en;q=0.9',
184 },
185 timeout: 15000,
186 });
187
188 const html = res.data;
189 const configMatch = html.match(/var\s+(?:ilovepdfConfig|iloveimgConfig)\s*=\s*({[\s\S]+?});/);
190 if (configMatch) {
191 try {
192 const config = JSON.parse(configMatch[1]);
193 if (config.token) return config.token;
194 } catch (_) {}
195 }
196
197 const tokenMatch = html.match(/"token"\s*:\s*"(ey[a-zA-Z0-9_\-\.]+)"/) || html.match(/token:\s*'(ey[a-zA-Z0-9_\-\.]+)'/);
198 if (tokenMatch) return tokenMatch[1];
199
200 throw new Error('Gagal mengekstrak JWT token dari iLoveIMG.');
201}
202
203async function upscaleImage(input, options = {}) {
204 const multiplier = Number(options.multiplier) === 4 ? 4 : 2;
205 const startTime = Date.now();
206
207 const token = await getUpscaleAuthToken();
208 const authHeaders = {
209 Authorization: `Bearer ${token}`,
210 Origin: 'https://www.iloveimg.com',
211 Referer: 'https://www.iloveimg.com/upscale-image',
212 };
213
214 const startRes = await axios.get('https://api.iloveimg.com/v1/start/upscaleimage', {
215 headers: authHeaders,
216 timeout: 15000,
217 });
218
219 const { server, task } = startRes.data;
220 if (!server || !task) {
221 throw new Error('Gagal memulai task upscale di server iLoveIMG.');
222 }
223
224 let fileBuffer = null;
225 let originalFilename = `image_${Date.now()}.jpg`;
226
227 if (Buffer.isBuffer(input)) {
228 fileBuffer = input;
229 if (options.filename) originalFilename = options.filename;
230 } else if (typeof input === 'string') {
231 if (input.startsWith('http://') || input.startsWith('https://')) {
232 const imgRes = await axios.get(input, {
233 responseType: 'arraybuffer',
234 headers: { 'User-Agent': UA },
235 });
236 fileBuffer = Buffer.from(imgRes.data);
237 const urlPath = new URL(input).pathname;
238 const baseName = path.basename(urlPath);
239 if (baseName && baseName.includes('.')) originalFilename = baseName;
240 } else if (fs.existsSync(input)) {
241 fileBuffer = fs.readFileSync(input);
242 originalFilename = path.basename(input);
243 } else {
244 throw new Error(`File input tidak ditemukan: "${input}"`);
245 }
246 } else {
247 throw new Error('Format input tidak valid.');
248 }
249
250 const uploadForm = new FormData();
251 uploadForm.append('task', task);
252 uploadForm.append('file', fileBuffer, { filename: originalFilename });
253
254 const uploadRes = await axios.post(`https://${server}/v1/upload`, uploadForm, {
255 headers: {
256 ...authHeaders,
257 ...uploadForm.getHeaders(),
258 },
259 maxBodyLength: Infinity,
260 maxContentLength: Infinity,
261 timeout: 60000,
262 });
263
264 const serverFilename = uploadRes.data.server_filename;
265 if (!serverFilename) {
266 throw new Error('Gagal mengunggah berkas ke server iLoveIMG.');
267 }
268
269 const processForm = new FormData();
270 processForm.append('task', task);
271 processForm.append('tool', 'upscaleimage');
272 processForm.append('files[0][server_filename]', serverFilename);
273 processForm.append('files[0][filename]', originalFilename);
274 processForm.append('multiplier', String(multiplier));
275 processForm.append('packaged_filename', `upscaled_${multiplier}x_${path.parse(originalFilename).name}`);
276
277 const processRes = await axios.post(`https://${server}/v1/process`, processForm, {
278 headers: {
279 ...authHeaders,
280 ...processForm.getHeaders(),
281 },
282 timeout: 90000,
283 });
284
285 let taskStatus = processRes.data.status;
286
287 if (taskStatus === 'TaskProcessing' || taskStatus === 'TaskWaiting') {
288 let attempts = 0;
289 while (taskStatus !== 'TaskSuccess' && attempts < 30) {
290 await new Promise((r) => setTimeout(r, 1500));
291 const checkRes = await axios.get(`https://${server}/v1/task/${task}`, {
292 headers: authHeaders,
293 timeout: 15000,
294 });
295 taskStatus = checkRes.data.status;
296 if (taskStatus === 'TaskError') {
297 throw new Error(checkRes.data.status_message || 'Terjadi kesalahan saat memproses upscale gambar.');
298 }
299 attempts++;
300 }
301 }
302
303 if (taskStatus !== 'TaskSuccess') {
304 throw new Error(`Status task tidak berhasil: ${taskStatus}`);
305 }
306
307 const downloadUrl = `https://${server}/v1/download/${task}`;
308 const duration = `${((Date.now() - startTime) / 1000).toFixed(2)}s`;
309
310 const downloadStream = await axios.get(downloadUrl, {
311 responseType: 'arraybuffer',
312 headers: authHeaders,
313 timeout: 60000,
314 });
315
316 const resultBuffer = Buffer.from(downloadStream.data);
317
318 return {
319 success: true,
320 status: 'success',
321 engine: 'iLoveIMG AI Super Resolution',
322 multiplier: `${multiplier}x`,
323 downloadUrl,
324 duration,
325 resultBuffer,
326 buffer: resultBuffer,
327 fileSize: `${(resultBuffer.length / (1024 * 1024)).toFixed(2)} MB`,
328 };
329}
330
331const iloveimgUpscale = upscaleImage;
332
333if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
334 const __exports = { compressImage: compressImage, getUpscaleAuthToken: getUpscaleAuthToken, upscaleImage: upscaleImage, iloveimgUpscale: iloveimgUpscale }
335 const __fns = Object.fromEntries(Object.entries(__exports).filter(([, v]) => typeof v === 'function'))
336 const __names = Object.keys(__fns)
337 if (__names.length === 0) {
338 console.log('Tidak ada fungsi yang bisa di-demo. Import modul ini dari kode lain.')
339 } else {
340 const __search = __names.find((n) => /search|cari/i.test(n))
341 const __name = __search || __names[0]
342 const __fn = __fns[__name]
343 const __isClass = /^class\s/.test(Function.prototype.toString.call(__fn))
344 const __defaultArgs = (() => {
345 const n = __name.toLowerCase()
346 if (/emoji/.test(n)) return [{ emoji: '😀😃' }]
347 if (/textpro|generate.*text|effect/.test(n)) return ['neon', 'Hello']
348 if (/image|wallpaper|search|query|anime|movie|manga|news|lyrics|wiki|quote|stalk|detail/.test(n)) return ['naruto']
349 if (/download|youtube|video|audio|music|spotify|tiktok|instagram|facebook|twitter|reels|terabox|media/.test(n)) return ['https://www.youtube.com/watch?v=dQw4w9WgXcQ']
350 if (/dork/.test(n)) return ['example.com', 'documents']
351 if (/tts|speech|prompt|chat|ask|translate/.test(n)) return ['Hello world']
352 if (/parse|format|normalize|list|features/.test(n)) return []
353 return ['test']
354 })()
355 let __args = __defaultArgs
356 if (process.argv.length > 2) __args = process.argv.slice(2).map((a) => { try { return JSON.parse(a) } catch { return a } })
357 if (__args.length === 0 && !__search && !__isClass && __fn.length > 0) {
358 console.log('Fungsi: ' + __names.join(', '))
359 console.log('Contoh: node ' + "iloveimg.js" + ' ' + __name + ' <arg>')
360 } else {
361 ;(async () => {
362 try {
363 const r = __isClass ? new __fn(...__args) : await __fn(...__args)
364 console.log(JSON.stringify(r, null, 2))
365 } catch (e) {
366 console.error('Error: ' + (e && e.message ? e.message : e))
367 process.exitCode = 1
368 }
369 })()
370 }
371 }
372}
373
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.