Closure-RI commited on
Commit
c1151ee
Β·
verified Β·
1 Parent(s): 5939545

Upload index.js

Browse files
Files changed (1) hide show
  1. index.js +1209 -1191
index.js CHANGED
@@ -1,1192 +1,1210 @@
1
- import axios from 'axios';
2
- import * as cheerio from 'cheerio';
3
- import { createRequire } from 'module';
4
- import os from 'os';
5
- import express from 'express';
6
- import { promisify, format } from 'util';
7
- import { fileTypeFromBuffer } from 'file-type';
8
- import ffmpeg from 'fluent-ffmpeg';
9
- import nodeID3 from 'node-id3';
10
- import ytdl from 'ytdl-core';
11
- import FormData from 'form-data';
12
- import fetch from 'node-fetch';
13
- import mime from "mime-types";
14
- const require = createRequire(import.meta.url);
15
- const fs = require('fs');
16
- const path = require('path');
17
- const { google } = require('googleapis');
18
- const puppeteer = require('puppeteer');
19
- import { fileURLToPath } from 'url';
20
- const PORT = process.env.PORT || 7860;
21
- const app = express();
22
- const readFileAsync = promisify(fs.readFile);
23
-
24
- const tempDir = path.join(os.tmpdir(), "temp");
25
- const fss = fs.promises;
26
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
27
- // Membuat direktori sementara jika belum ada
28
- (async () => {
29
- if (!fs.existsSync(tempDir)) {
30
- await fss.mkdir(tempDir, { recursive: true });
31
- }
32
- })();
33
- const { exec } = require('child_process');
34
- const writeFileAsync = promisify(fs.writeFile);
35
- const execPromise = promisify(exec);
36
- const youtube = google.youtube({ version: 'v3', auth: 'AIzaSyBPkpdJEGtAHebbaP3_CcA1_urfMFfeLLg' });
37
- const bodyParser = require('body-parser');
38
- app.use(bodyParser.json());
39
-
40
-
41
-
42
- const tempDirBase = tempDir
43
- const https = require('https');
44
-
45
- const agent = new https.Agent({
46
- rejectUnauthorized: false // Nonaktifkan verifikasi sertifikat
47
- });
48
-
49
- app.use('/temp', express.static(tempDir));
50
- app.use(express.json());
51
- app.use(express.raw({ type: '*/*', limit: '10mb' })); // Untuk menangani buffer dan data binary
52
- app.use(express.urlencoded({ extended: true }));
53
-
54
-
55
- app.all('/axios/:method/*', async (req, res) => {
56
- const { method } = req.params;
57
- const targetUrl = decodeURIComponent(req.params[0]); // Menangani URL setelah /:method/
58
- const responseType = req.query.responseType || ''; // Menangani opsi responseType
59
-
60
- let option = {
61
- headers: {
62
- ...req.headers, // Menyalin semua header dari permintaan asli
63
- 'User-Agent': req.headers['user-agent'] || 'Mozilla/5.0 (Linux; Android 12; SM-S908B Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.58 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/357.0.0.23.115;] WhatsApp/1.2.3', // Menambahkan custom user-agent
64
- },
65
- httpsAgent: agent
66
- };
67
-
68
- if (responseType) {
69
- option.responseType = responseType;
70
- }
71
-
72
- try {
73
- let response;
74
- if (method.toLowerCase() === 'get') {
75
- response = await axios.get(targetUrl, option);
76
- } else if (method.toLowerCase() === 'post') {
77
- option.data = req.body;
78
- response = await axios.post(targetUrl, req.body, option);
79
- } else {
80
- res.status(405).json({ error: 'Method not allowed' });
81
- return;
82
- }
83
-
84
- // Mengambil Content-Type dari header respons
85
- const mimeType = response.headers['content-type'];
86
- const buffer = Buffer.from(response.data, 'binary');
87
-
88
- res.status(response.status);
89
- res.set(response.headers); // Set headers dari respons API
90
-
91
- // Menangani respons berdasarkan Content-Type
92
- if (mimeType && (mimeType.includes('text') || mimeType.includes('json') || mimeType.includes('html') || mimeType.includes('plain'))) {
93
- // Kirim data sebagai teks
94
- res.send(buffer.toString('utf-8'));
95
- } else {
96
- // Kirim file binary, termasuk PDF
97
- res.setHeader('Content-Length', buffer.length);
98
- res.send(buffer);
99
- }
100
- } catch (error) {
101
- console.error('Error:', error.response ? error.response.data : error.message);
102
-
103
- const statusCode = error.response ? error.response.status : 500;
104
- const errorMessage = error.response ? error.response.data : error.message;
105
-
106
- res.status(statusCode).json({
107
- error: errorMessage
108
- });
109
- }
110
- });
111
-
112
- app.get("/", (req, res) => {
113
- res.type("json");
114
- const keluaran = {
115
- success: true,
116
- author: "Nex",
117
- data: {
118
- igdl: "/igdl",
119
- twdl: "/twdl"
120
- },
121
- };
122
- res.send(keluaran);
123
- });
124
-
125
- app.post("/eval", async (req, res) => {
126
- const { code } = req.body;
127
- const { responseType = "text" } = req.query;
128
- let __dirname = path.dirname(fileURLToPath(import.meta.url));
129
- let require = createRequire(__dirname);
130
-
131
- let _return;
132
- try {
133
- _return = /await/i.test(code)
134
- ? eval("(async() => { " + code + " })()")
135
- : eval(code);
136
- } catch (e) {
137
- _return = e;
138
- }
139
-
140
- // Handle Buffer atau Base64
141
- if (Buffer.isBuffer(_return) || typeof _return === "string" && _return.startsWith("data:")) {
142
- const buffer = Buffer.isBuffer(_return)
143
- ? _return
144
- : Buffer.from(_return.split(",")[1], "base64");
145
-
146
- const fileType = await fileTypeFromBuffer(buffer);
147
- const mimeType = fileType ? fileType.mime : "application/octet-stream";
148
- const ext = fileType ? fileType.ext : "bin";
149
- const filename = `Nex - ${Date.now()}.${ext}`;
150
-
151
- res.setHeader("Content-Type", mimeType);
152
- res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
153
- return res.send(buffer);
154
- }
155
-
156
- // Handle respon berdasarkan responseType
157
- switch (responseType) {
158
- case "json":
159
- try {
160
- const jsonFormatted = typeof _return === "string" ? JSON.parse(_return) : _return;
161
- return res.json(format(jsonFormatted));
162
- } catch (err) {
163
- return res.json({ error: "Invalid JSON format", result: format(_return) });
164
- }
165
-
166
- case "file":
167
- const filePath = path.join(__dirname, `Nex - ${Date.now()}.txt`);
168
- fs.writeFileSync(filePath, _return.toString());
169
- return res.download(filePath, () => fs.unlinkSync(filePath));
170
-
171
- case "text":
172
- default:
173
- res.setHeader("Content-Type", "text/plain; charset=utf-8");
174
- return res.send(_return.toString());
175
- }
176
- });
177
-
178
-
179
-
180
-
181
-
182
- // Fungsi untuk menghasilkan IP acak
183
- const generateRandomIP = () => {
184
- const octet = () => Math.floor(Math.random() * 256);
185
- return `${octet()}.${octet()}.${octet()}.${octet()}`;
186
- };
187
-
188
- // Fungsi untuk upload file
189
- async function uploader(buffer) {
190
- const { ext } = await fileTypeFromBuffer(buffer);
191
- const bodyForm = new FormData();
192
- bodyForm.append('file', buffer, `file.${ext}`);
193
-
194
- const response = await fetch('https://aemt.me/api/upload.php', {
195
- method: 'POST',
196
- body: bodyForm,
197
- });
198
-
199
- return {
200
- status: response.status,
201
- creator: 'Nex',
202
- result: await response.json(),
203
- };
204
- }
205
-
206
- // Fungsi untuk mendapatkan URL thumbnail HD
207
- async function getHDThumbnailUrl(videoId) {
208
- try {
209
- const response = await youtube.videos.list({ part: 'snippet', id: videoId });
210
- return response.data.items[0].snippet.thumbnails.maxres.url;
211
- } catch (error) {
212
- console.error('Error fetching HD thumbnail URL:', error.message);
213
- return null;
214
- }
215
- }
216
-
217
- const getVideoDetailsWithApi = async (videoId) => {
218
- const url = `https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId}&key=AIzaSyBPkpdJEGtAHebbaP3_CcA1_urfMFfeLLg`;
219
-
220
- try {
221
- const response = await axios.get(url);
222
- const video = response.data.items[0];
223
-
224
- const title = video.snippet.title;
225
- const description = video.snippet.description;
226
- const thumbnail = video.snippet.thumbnails.high.url;
227
- const channelTitle = video.snippet.channelTitle;
228
- const publishedAt = video.snippet.publishedAt;
229
- const tags = video.snippet.tags;
230
-
231
- const videoDetails = {
232
- title: title,
233
- description: description,
234
- thumbnail: thumbnail,
235
- channelTitle: channelTitle,
236
- publishedAt: publishedAt,
237
- tags: tags,
238
- };
239
-
240
- return videoDetails
241
- } catch (error) {
242
- console.error('An error occurred:', error);
243
- }
244
- };
245
-
246
- // Fungsi untuk mendapatkan ID video dari URL
247
- async function GetId(data) {
248
- const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtu(?:be\.com\/(?:watch\?(?:v=|vi=)|v\/|vi\/)|\.be\/|be\.com\/embed\/|be\.com\/shorts\/)|youtube\.com\/\?(?:v=|vi=))([\w-]{11})/;
249
- const res = regex.exec(data);
250
- if (res && res[1]) return res[1];
251
- throw new Error("Please check the URL you have entered");
252
- }
253
-
254
- // Fungsi untuk menambahkan tag ID3 ke file audio
255
- async function addAudioTags(media, title, artist, year, imagecover) {
256
- try {
257
- let audioBuffer;
258
- if (typeof media === 'string') {
259
- const response = await axios.get(media, { responseType: 'arraybuffer', maxContentLength: -1 });
260
- audioBuffer = Buffer.from(response.data);
261
- } else if (media instanceof Buffer) {
262
- audioBuffer = media;
263
- } else {
264
- throw new Error('Media harus berupa URL string atau Buffer.');
265
- }
266
-
267
- const randomFilename = generateRandomName(10) + '.mp3';
268
- const tmpFilePath = path.join(tempDir, randomFilename);
269
- fs.writeFileSync(tmpFilePath, audioBuffer);
270
-
271
- const tags = { title, artist, year };
272
- if (typeof imagecover === 'string') {
273
- const response = await axios.get(imagecover, { responseType: 'arraybuffer' });
274
- const coverBuffer = Buffer.from(response.data);
275
- tags.image = {
276
- mime: 'image/jpeg',
277
- type: { id: 3, name: 'Front Cover' },
278
- description: 'Cover',
279
- imageBuffer: coverBuffer
280
- };
281
- } else if (imagecover instanceof Buffer) {
282
- tags.image = {
283
- mime: 'image/jpeg',
284
- type: { id: 3, name: 'Front Cover' },
285
- description: 'Cover',
286
- imageBuffer: imagecover
287
- };
288
- }
289
-
290
- const success = nodeID3.write(tags, tmpFilePath);
291
- console[success ? 'log' : 'error'](success ? 'Tag ID3 berhasil diubah!' : 'Gagal mengubah tag ID3.');
292
-
293
- return { msg: `Audio berhasil diubah.`, path: `${tmpFilePath}` };
294
- } catch (error) {
295
- console.error('Terjadi kesalahan:', error);
296
- throw new Error('Terjadi kesalahan saat mengubah audio.');
297
- }
298
- }
299
-
300
- // Fungsi untuk menghasilkan nama acak
301
- function generateRandomName(length) {
302
- const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
303
- let randomName = '';
304
- for (let i = 0; i < length; i++) {
305
- randomName += characters.charAt(Math.floor(Math.random() * characters.length));
306
- }
307
- return randomName;
308
- }
309
-
310
-
311
- async function fetchCobaltOnly(url, opts = {}) {
312
- try {
313
- const response = await axios.post('https://cobalt.siputzx.my.id/', { url, ...opts }, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } } );
314
- return response.data;
315
- } catch (error) {
316
- if (error.response) {
317
- const contentType = error.response.headers['content-type'];
318
- if (contentType && contentType.includes('json')) {
319
- throw error.response.data.message || 'An error occurred';
320
- }
321
- throw error.response.statusText;
322
- }
323
- throw error.message;
324
- }
325
- }
326
-
327
-
328
-
329
- const servers = [
330
- "https://cobalt.siputzx.my.id/",
331
- "https://c.blahaj.ca/",
332
- "https://api.co.waow.cat/",
333
- "https://cobalt-api.kwiatekmiki.com",
334
- "https://cobalt-backend.canine.tools/",
335
- "https://cobalt.api.timelessnesses.me/",
336
- "https://capi.3kh0.net"
337
- ];
338
-
339
- async function cobalt(config) {
340
- try {
341
- if (!(typeof config === "object")) {
342
- throw new Error("Invalid config input, config must be a JSON object!");
343
- }
344
-
345
- config = {
346
- url: config?.url || null,
347
- videoQuality: config?.videoQuality || "720",
348
- audioFormat: config?.audioFormat || "mp3",
349
- audioBitrate: config?.audioBitrate || "128",
350
- filenameStyle: config?.filenameStyle || "classic",
351
- downloadMode: config?.downloadMode || "auto",
352
- youtubeVideoCodec: config?.youtubeVideoCodec || "h264",
353
- youtubeDubLang: config?.youtubeDubLang || "en",
354
- alwaysProxy: config?.alwaysProxy || false,
355
- disableMetadata: config?.disableMetadata || false,
356
- tiktokFullAudio: config?.tiktokFullAudio || true,
357
- tiktokH265: config?.tiktokH265 || true,
358
- twitterGif: config?.twitterGif || true,
359
- youtubeHLS: config?.youtubeHLS || false,
360
- };
361
-
362
- if (!config.url) {
363
- throw new Error("Missing URL input!");
364
- }
365
-
366
- for (let i = 0; i < servers.length; i++) {
367
- try {
368
- console.log(`Trying server: ${servers[i]}`); // Log server yang dicoba
369
- const response = await axios.post(servers[i], config, {
370
- headers: {
371
- accept: "application/json",
372
- contentType: "application/json",
373
- },
374
- });
375
-
376
- const data = response.data;
377
- if (data.status === "error") {
378
- throw new Error("Failed to fetch content from server.");
379
- }
380
-
381
- console.log(`Success with server: ${servers[i]}`); // Log server sukses
382
- return {
383
- success: true,
384
- result: data,
385
- };
386
- } catch (error) {
387
- if (i === servers.length - 1) {
388
- // Jika sudah mencoba semua server
389
- throw error;
390
- }
391
- console.warn(`Server ${servers[i]} failed. Trying next server...`); // Log server gagal
392
- }
393
- }
394
- } catch (error) {
395
- return {
396
- success: false,
397
- errors: error.message || error,
398
- };
399
- }
400
- }
401
-
402
-
403
-
404
- async function getAudioMP3Url(videoUrl) {
405
- try {
406
- const id_video = await GetId(videoUrl);
407
- const infoVids = await getVideoDetailsWithApi(id_video);
408
-
409
- const video = await axios.get("https://api.siputzx.my.id/api/dl/youtube/mp3?url=" + videoUrl)
410
-
411
- /*
412
- const video = await fetchCobaltOnly(videoUrl, { downloadMode: "audio", audioBitrate: "128", filenameStyle: "pretty", audioFormat: "mp3"})
413
- console.log(video)
414
- */
415
-
416
- // Unduh file audio terlebih dahulu
417
- /*
418
- const video = await cobalt({
419
- url: videoUrl,
420
- downloadMode: "audio",
421
- filenameStyle: "pretty",
422
- audioFormat: "mp3",
423
- audioBitrate: "128"
424
- })
425
- */
426
- const path_audio = path.join(tempDir, generateRandomName(10) + '.mp3');
427
- const path_audio_edit = path_audio.replace('.mp3', '_edit.mp3');
428
-
429
- // Download file audio
430
- const headers = {
431
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36',
432
- 'Referer': 'https://cobalt.tools/pustaka/'
433
- };
434
- const response = await axios.get(video.data.data, { responseType: 'arraybuffer', headers });
435
- fs.writeFileSync(path_audio, response.data);
436
-
437
- // Periksa apakah file input valid
438
- if (!fs.existsSync(path_audio)) {
439
- throw new Error('File audio tidak ditemukan setelah diunduh.');
440
- }
441
- if (fs.statSync(path_audio).size === 0) {
442
- throw new Error('File audio kosong atau rusak.');
443
- }
444
-
445
- // Debugging tambahan: coba cek format file
446
- console.log(`File audio diunduh: ${path_audio}, size: ${fs.statSync(path_audio).size} bytes`);
447
-
448
- // Tambahkan metadata ke file yang diunduh
449
- await new Promise((resolve, reject) => {
450
- ffmpeg(path_audio)
451
- .outputOptions(['-acodec libmp3lame', '-ab 128k', '-ar 44100'])
452
- .on('start', (commandLine) => {
453
- console.log('FFmpeg command:', commandLine); // Log perintah FFmpeg
454
- })
455
- .on('stderr', (stderrLine) => {
456
- console.error('FFmpeg stderr:', stderrLine); // Log error FFmpeg
457
- })
458
- .on('end', async () => {
459
- try {
460
- // Tambahkan metadata
461
- const buffer = fs.readFileSync(path_audio_edit); // Ambil file hasil edit
462
- const edited = await addAudioTags(buffer, infoVids.title, infoVids.channelTitle, 2024, infoVids.thumbnail);
463
-
464
- // Ganti file lama dengan file yang sudah diedit
465
- const buffer2 = fs.readFileSync(edited.path);
466
- fs.writeFileSync(path_audio, buffer2);
467
- fs.unlinkSync(path_audio_edit); // Hapus file sementara
468
-
469
- resolve();
470
- } catch (error) {
471
- reject(error);
472
- }
473
- })
474
- .on('error', (err) => {
475
- console.error('FFmpeg conversion error:', err);
476
- reject(err);
477
- })
478
- .save(path_audio_edit); // Simpan sementara dengan nama _edit.mp3
479
- });
480
-
481
- // Kembalikan hasil akhir
482
- return {
483
- status: 200,
484
- title: infoVids.title,
485
- result: {
486
- fileName: video.filename || infoVids.title + ".mp3",
487
- url_path: `https://${process.env.SPACE_HOST}/temp/${path.basename(path_audio)}`,
488
- curl_path: `https://${process.env.SPACE_HOST}/temp/${path.basename(path_audio)}?download=1&filename=${infoVids.title}`,
489
- path: path_audio
490
- },
491
- infoVids
492
- };
493
- } catch (error) {
494
- console.error('Error:', error);
495
- throw new Error('Failed to process audio URL');
496
- }
497
- }
498
-
499
-
500
-
501
-
502
-
503
-
504
-
505
- app.get('/ytmp3', async (req, res) => {
506
- try {
507
- const { url } = req.query;
508
- if (!url) return res.status(400).json({ error: 'Parameter url is required' });
509
-
510
- let result = await getAudioMP3Url(url);
511
- res.json(result);
512
-
513
- // Menghapus file setelah 10 menit
514
- try {
515
- await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
516
- await fss.unlink(result.result.path);
517
- console.log(`File ${result.result.path} deleted.`);
518
- } catch (error) {
519
- console.error(`Error deleting file ${result.result.path}:`, error);
520
- }
521
- } catch (error) {
522
- console.error('Error processing request:', error);
523
- res.status(500).json({
524
- error: 'Failed to process request\n' + error
525
- });
526
- }
527
- });
528
-
529
-
530
-
531
- async function fetchHtml(url) {
532
- // Launch browser dengan mode headless
533
- const browser = await puppeteer.launch();
534
-
535
- // Buat page baru
536
- const page = await browser.newPage();
537
-
538
- // Set User Agent untuk menghindari deteksi bot
539
- //await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.3');
540
-
541
- await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
542
-
543
- // Navigasi ke URL yang diinginkan
544
- //await page.goto(url);
545
-
546
- await page.goto(url, { waitUntil: 'networkidle2' });
547
-
548
- // Tunggu sampai page selesai loading
549
- //await page.waitForNavigation({ waitUntil: 'networkidle2' });
550
-
551
- // Ambil HTML dari page
552
- const html = await page.content();
553
-
554
- // Tutup browser
555
- await browser.close();
556
-
557
- // Return HTML
558
- return html;
559
- }
560
-
561
- app.get('/html', async (req, res) => {
562
- try {
563
- const { url } = req.query;
564
- if (!url) return res.status(400).json({ error: 'Parameter url is required' });
565
- let result = await fetchHtml(url);
566
- res.send(result);
567
- } catch (error) {
568
- console.error('Error processing request:', error);
569
- res.status(500).json({
570
- error: 'Failed to process request\n' + error
571
- });
572
- }
573
- });
574
-
575
-
576
- async function XnDl(url) {
577
- const browser = await puppeteer.launch({
578
- headless: true,
579
- args: ['--no-sandbox', '--disable-setuid-sandbox','--incognito'],
580
- timeout: 60000 // Timeout untuk peluncuran browser
581
- });
582
-
583
- try {
584
- const context = await browser.createBrowserContext();
585
- // Create a new page inside context.
586
- const page = await context.newPage();
587
- await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
588
-
589
- await page.goto(url.replace("xnxx.com", "xnxxvideodownload.com"), {
590
- waitUntil: 'domcontentloaded',
591
- timeout: 60000 // Timeout untuk navigasi
592
- });
593
-
594
- await page.waitForNavigation({
595
- waitUntil: 'networkidle0',
596
- timeout: 60000 // Timeout untuk menunggu navigasi selesai
597
- });
598
-
599
- const data = await page.evaluate(() => {
600
- const title = document.querySelector("body > main > section.e.j.d2.dsection > h2")?.textContent || '';
601
- const thumbnail = document.querySelector("body > main > section.e.j.d2.dsection > div > div.thumbdiv > img")?.src || '';
602
- const url = document.querySelector("body > main > section.e.j.d2.dsection > div > div.thumbdiv > a")?.href || '';
603
-
604
- const table = document.getElementById('dtable')?.getElementsByTagName('table')[0];
605
- const videoDownload = [];
606
-
607
- if (table) {
608
- for (let i = 0; i < table.rows.length; i++) {
609
- const row = table.rows[i];
610
- const rowData = {
611
- quality: row.cells[0]?.innerText || '',
612
- ext: row.cells[1]?.innerText || '',
613
- url: row.cells[2]?.getElementsByTagName('a')[0]?.href || ''
614
- };
615
- videoDownload.push(rowData);
616
- }
617
- }
618
-
619
- return { title, thumbnail, url, videoDownload };
620
- });
621
-
622
- return data;
623
- } catch (error) {
624
- console.error('Error:', error);
625
- return null;
626
- } finally {
627
- await browser.close();
628
- }
629
- }
630
-
631
-
632
- app.get('/xnxx', async (req, res) => {
633
- try {
634
- const { url } = req.query;
635
- if (!url) return res.status(400).json({ error: 'Parameter url is required' });
636
- let result = await XnDl(url);
637
- res.send(result);
638
- } catch (error) {
639
- console.error('Error processing request:', error);
640
- res.status(500).json({
641
- error: 'Failed to process request\n' + error
642
- });
643
- }
644
- });
645
-
646
-
647
- /*
648
- ┏┓┏━┓┏━━━┓┏━┓┏━┓┏━━┓┏┓┏━┓┏┓╋┏┓
649
- ┃┃┃┏┛┃┏━┓┃┃┃┗┛┃┃┗┫┣┛┃┃┃┏┛┃┃╋┃┃
650
- ┃┗┛┛╋┃┃╋┃┃┃┏┓┏┓┃╋┃┃╋┃┗┛┛╋┃┃╋┃┃
651
- ┃┏┓┃╋┃┃╋┃┃┃┃┃┃┃┃╋┃┃╋┃┏┓┃╋┃┃╋┃┃
652
- ┃┃┃┗┓┃┗━┛┃┃┃┃┃┃┃┏┫┣┓┃┃┃┗┓┃┗━┛┃
653
- ┗┛┗━┛┗━━━┛┗┛┗┛┗┛┗━━┛┗┛┗━┛┗━━━┛
654
- */
655
-
656
- function generateRandomID(length = 8) {
657
- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
658
- let result = '';
659
- for (let i = 0; i < length; i++) {
660
- result += characters.charAt(Math.floor(Math.random() * characters.length));
661
- }
662
- return result;
663
- }
664
-
665
- async function komiku_download(url) {
666
- const instanceID = generateRandomID();
667
- const tempDir = path.join(tempDirBase, instanceID);
668
- await fss.mkdir(tempDir);
669
-
670
- // Extracting the title from the URL
671
- const title = url.split('/').filter(part => part).pop();
672
-
673
- try {
674
- const response = await axios.get(url);
675
- const html = response.data;
676
- const $ = cheerio.load(html);
677
- const imgList = [];
678
-
679
- $('#Baca_Komik img').each((index, element) => {
680
- const src = $(element).attr('src');
681
- imgList.push({ path: src });
682
- });
683
-
684
- await processImages(imgList, tempDir, instanceID);
685
- const pdfPath = await createPDF(instanceID, tempDir);
686
-
687
- console.log(`PDF berhasil dibuat: ${pdfPath}`);
688
- return { path: pdfPath, title: title, url: `https://${process.env.SPACE_HOST}/temp/${path.basename(pdfPathq)}` };
689
- } catch (error) {
690
- console.log(error);
691
- throw error;
692
- } finally {
693
- await fss.rmdir(tempDir, { recursive: true });
694
- }
695
- }
696
-
697
- async function downloadImage(image, tempDir, instanceID) {
698
- const response = await axios.get(image.path, { responseType: 'arraybuffer' });
699
- const imagePath = path.join(tempDir, `image_${instanceID}_${Date.now()}_${Math.floor(Math.random() * 1000)}.jpg`);
700
- await writeFileAsync(imagePath, response.data);
701
-
702
- const imageHeight = await getImageHeight(imagePath);
703
- const newHeight = Math.floor(imageHeight * 0.7);
704
- const command = `convert ${imagePath} -resize 720x${newHeight}! -quality 75 -background white -gravity center -extent 720x${newHeight} ${imagePath}`;
705
- await execPromise(command);
706
-
707
- return imagePath;
708
- }
709
-
710
- async function getImageHeight(imagePath) {
711
- const { stdout } = await execPromise(`identify -format "%h" ${imagePath}`);
712
- return parseInt(stdout.trim());
713
- }
714
-
715
- async function processImages(imgList, tempDir, instanceID) {
716
- const maxImagesPerPage = 10; // Maksimal 10 gambar per halaman
717
- let partIndex = 0;
718
- let partImages = [];
719
-
720
- for (let i = 0; i < imgList.length; i++) {
721
- const imagePath = await downloadImage(imgList[i], tempDir, instanceID);
722
- partImages.push(imagePath);
723
-
724
- if (partImages.length >= maxImagesPerPage) {
725
- await combineAndSave(partImages, partIndex, tempDir, instanceID);
726
- partImages = [];
727
- partIndex++;
728
- }
729
- }
730
-
731
- // Jika masih ada gambar yang belum diproses
732
- if (partImages.length > 0) {
733
- await combineAndSave(partImages, partIndex, tempDir, instanceID);
734
- }
735
- }
736
-
737
- async function combineAndSave(imagePaths, partIndex, tempDir, instanceID) {
738
- const combinedImagePath = path.join(tempDir, `combined_part_${instanceID}_${partIndex}.jpg`);
739
- const command = `convert ${imagePaths.join(' ')} -append -quality 75 ${combinedImagePath}`;
740
- await execPromise(command);
741
-
742
- imagePaths.forEach(fs.unlinkSync);
743
-
744
- return combinedImagePath;
745
- }
746
-
747
- async function createPDF(instanceID, tempDir) {
748
- const combinedParts = fs.readdirSync(tempDir).filter(file => file.startsWith(`combined_part_${instanceID}_`));
749
- const combinedImagesPath = combinedParts.map(file => path.join(tempDir, file)).join(' ');
750
-
751
- const pdfPath = path.join(tempDir, `${instanceID}.pdf`);
752
- const createPDFCommand = `convert ${combinedImagesPath} ${pdfPath}`;
753
- await execPromise(createPDFCommand);
754
-
755
- return pdfPath;
756
- }
757
-
758
- app.get('/komiku/download', async (req, res) => {
759
- try {
760
- const { url } = req.query;
761
- if (!url) return res.status(400).json({ error: 'Parameter url is required' });
762
-
763
- let result = await komiku_download(url);
764
- res.json(result);
765
-
766
- // Menghapus file setelah 10 menit
767
- try {
768
- await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
769
- await fss.unlink(result.path);
770
- console.log(`File ${result.path} deleted.`);
771
- } catch (error) {
772
- console.error(`Error deleting file ${result.path}:`, error);
773
- }
774
- } catch (error) {
775
- console.error('Error processing request:', error);
776
- res.status(500).json({
777
- error: 'Failed to process request\n' + error
778
- });
779
- }
780
- });
781
- /*
782
- V2 V2 V2 V2
783
- */
784
-
785
- async function komiku_downloadV2(url) {
786
- const instanceID = generateRandomID();
787
- const tempDir = path.join(tempDirBase, instanceID);
788
- await fss.mkdir(tempDir);
789
-
790
- // Extracting the title from the URL
791
- const title = url.split('/').filter(part => part).pop();
792
-
793
- let browser;
794
- try {
795
- browser = await puppeteer.launch({
796
- headless: true,
797
- args: ['--no-sandbox', '--disable-setuid-sandbox']
798
- });
799
- const page = await browser.newPage();
800
- await page.goto(url, { waitUntil: 'networkidle2' });
801
-
802
- // Extracting images from the page
803
- const imgList = await page.evaluate(() => {
804
- return Array.from(document.querySelectorAll('#Baca_Komik img')).map(img => img.src);
805
- });
806
-
807
- const images = imgList.map(src => ({ path: src }));
808
-
809
- await processImagesV2(images, tempDir, instanceID);
810
- const pdfPath = await createPDFV2(instanceID, tempDir);
811
-
812
- console.log(`PDF berhasil dibuat: ${pdfPath}`);
813
- return { path: pdfPath, title: title, url: `https://${process.env.SPACE_HOST}/temp/${path.basename(pdfPath)}` };
814
- } catch (error) {
815
- console.log(error);
816
- throw error;
817
- } finally {
818
- if (browser) {
819
- await browser.close();
820
- }
821
- await fss.rmdir(tempDir, { recursive: true });
822
- }
823
- }
824
-
825
- async function downloadImageV2(image, tempDir, instanceID) {
826
- const response = await puppeteer.download(image.path, { responseType: 'arraybuffer' });
827
- const imagePath = path.join(tempDir, `image_${instanceID}_${Date.now()}_${Math.floor(Math.random() * 1000)}.jpg`);
828
- await writeFileAsync(imagePath, response);
829
-
830
- const imageHeight = await getImageHeightV2(imagePath);
831
- const newHeight = Math.floor(imageHeight * 0.7);
832
- const command = `convert ${imagePath} -resize 720x${newHeight}! -quality 75 -background white -gravity center -extent 720x${newHeight} ${imagePath}`;
833
- await execPromise(command);
834
-
835
- return imagePath;
836
- }
837
-
838
- async function getImageHeightV2(imagePath) {
839
- const { stdout } = await execPromise(`identify -format "%h" ${imagePath}`);
840
- return parseInt(stdout.trim());
841
- }
842
-
843
- async function processImagesV2(imgList, tempDir, instanceID) {
844
- const maxImagesPerPage = 10; // Maksimal 10 gambar per halaman
845
- let partIndex = 0;
846
- let partImages = [];
847
-
848
- for (let i = 0; i < imgList.length; i++) {
849
- const imagePath = await downloadImageV2(imgList[i], tempDir, instanceID);
850
- partImages.push(imagePath);
851
-
852
- if (partImages.length >= maxImagesPerPage) {
853
- await combineAndSaveV2(partImages, partIndex, tempDir, instanceID);
854
- partImages = [];
855
- partIndex++;
856
- }
857
- }
858
-
859
- // Jika masih ada gambar yang belum diproses
860
- if (partImages.length > 0) {
861
- await combineAndSaveV2(partImages, partIndex, tempDir, instanceID);
862
- }
863
- }
864
-
865
- async function combineAndSaveV2(imagePaths, partIndex, tempDir, instanceID) {
866
- const combinedImagePath = path.join(tempDir, `combined_part_${instanceID}_${partIndex}.jpg`);
867
- const command = `convert ${imagePaths.join(' ')} -append -quality 75 ${combinedImagePath}`;
868
- await execPromise(command);
869
-
870
- imagePaths.forEach(fs.unlinkSync);
871
-
872
- return combinedImagePath;
873
- }
874
-
875
- async function createPDFV2(instanceID, tempDir) {
876
- const combinedParts = fs.readdirSync(tempDir).filter(file => file.startsWith(`combined_part_${instanceID}_`));
877
- const combinedImagesPath = combinedParts.map(file => path.join(tempDir, file)).join(' ');
878
-
879
- const pdfPath = path.join(tempDir, `${instanceID}.pdf`);
880
- const createPDFCommand = `convert ${combinedImagesPath} ${pdfPath}`;
881
- await execPromise(createPDFCommand);
882
-
883
- return pdfPath;
884
- }
885
-
886
-
887
- app.get('/komiku/downloadV2', async (req, res) => {
888
- try {
889
- const { url } = req.query;
890
- if (!url) return res.status(400).json({ error: 'Parameter url is required' });
891
- let result = await komiku_downloadV2(url);
892
- res.json(result);
893
-
894
- // Menghapus file setelah 10 menit
895
- try {
896
- await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
897
- await fss.unlink(result.path);
898
- console.log(`File ${result.path} deleted.`);
899
- } catch (error) {
900
- console.error(`Error deleting file ${result.path}:`, error);
901
- }
902
- } catch (error) {
903
- console.error('Error processing request:', error);
904
- res.status(500).json({
905
- error: 'Failed to process request\n' + error
906
- });
907
- }
908
- });
909
- /***********/
910
-
911
- async function getLatestKomik(page) {
912
- const url = `https://api.komiku.id/manga/page/${page}/`;
913
- const headers = {
914
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36',
915
- 'Referer': 'https://komiku.id/pustaka/'
916
- };
917
-
918
- try {
919
- const response = await axios.get(url, { headers });
920
- const $ = cheerio.load(response.data);
921
- const mangaArray = [];
922
-
923
- // Scraping data
924
- $('.bge').each((index, element) => {
925
- const title = $(element).find('.kan h3').text().trim();
926
- const link_komik = $(element).find('.bgei a').attr('href');
927
- const imgSrc = $(element).find('.bgei img').attr('src');
928
- const type = $(element).find('.tpe1_inf b').text().trim();
929
- const type2 = $(element).find('.tpe1_inf').text().trim();
930
- const description = $(element).find('.kan p').text().trim();
931
- const readersInfo = $(element).find('.judul2').text().trim();
932
- const latestChapter = "https://komiku.id" + $(element).find('.new1:last-child a').attr('href');
933
-
934
- mangaArray.push({
935
- title,
936
- link_komik,
937
- imgSrc,
938
- type,
939
- type2,
940
- description,
941
- readersInfo,
942
- latestChapter
943
- });
944
- });
945
-
946
- return mangaArray;
947
- } catch (error) {
948
- console.error('Error fetching the URL', error);
949
- throw error;
950
- }
951
- }
952
-
953
- async function GetKomik(url) {
954
- try {
955
- const response = await axios.get(url);
956
- const $ = cheerio.load(response.data);
957
-
958
- const cover = $('#Informasi > div > img').attr('src');
959
- const judul = $('#Informasi > table > tbody > tr:nth-child(1) > td:nth-child(2)').text().trim();
960
- const jenis = $('#Informasi > table > tbody > tr:nth-child(3) > td:nth-child(2) > b').text().trim();
961
- const konsepCerita = $('#Informasi > table > tbody > tr:nth-child(4) > td:nth-child(2)').text().trim();
962
- const author = $('#Informasi > table > tbody > tr:nth-child(5) > td:nth-child(2)').text().trim();
963
- const status = $('#Informasi > table > tbody > tr:nth-child(6) > td:nth-child(2)').text().trim();
964
- const sinopsis = $('#Judul > p.desc').text().trim();
965
-
966
- const genreElements = $('#Informasi > ul > li').map((i, el) => $(el).text().trim()).get();
967
-
968
- const chapterElements = $('#daftarChapter > tr').map((i, el) => {
969
- if (i === 0) {
970
- return null;
971
- }
972
- return {
973
- judulSeries: $(el).find('td.judulseries > a').text().trim(),
974
- tanggalUpdate: $(el).find('td.tanggalseries').text().trim(),
975
- url: "https://komiku.id" + $(el).find('td.judulseries > a').attr('href')
976
- };
977
- }).get().filter(chapter => chapter !== null);
978
-
979
- const mangaInfo = {
980
- cover,
981
- judul,
982
- sinopsis,
983
- jenis,
984
- konsepCerita,
985
- author,
986
- status,
987
- genres: genreElements,
988
- chapters: chapterElements
989
- };
990
-
991
- return mangaInfo;
992
- } catch (error) {
993
- console.error('Error fetching the URL', error);
994
- throw error;
995
- }
996
- }
997
-
998
-
999
- app.get('/komiku/latest', async (req, res) => {
1000
- try {
1001
- const { page } = req.query;
1002
- if (!page) return res.status(400).json({ error: 'Parameter page is required' });
1003
-
1004
- let result = await getLatestKomik(page);
1005
- res.json(result);
1006
- } catch (error) {
1007
- console.error('Error processing request:', error);
1008
- res.status(500).json({
1009
- error: 'Failed to process request\n' + error
1010
- });
1011
- }
1012
- });
1013
-
1014
- app.get('/komiku', async (req, res) => {
1015
- try {
1016
- const { url } = req.query;
1017
- if (!url) return res.status(400).json({ error: 'Parameter url is required' });
1018
-
1019
- let result = await GetKomik(url);
1020
- res.json(result);
1021
- } catch (error) {
1022
- console.error('Error processing request:', error);
1023
- res.status(500).json({
1024
- error: 'Failed to process request\n' + error
1025
- });
1026
- }
1027
- });
1028
-
1029
-
1030
- app.post("/cobalt", async (req, res) => {
1031
- const config = req.body;
1032
- try {
1033
- if (!config.url) {
1034
- return res.status(400).json({
1035
- success: false,
1036
- message: "Missing 'url' in the request body.",
1037
- });
1038
- }
1039
- const result = await cobalt(config);
1040
- if (result.success) {
1041
- return res.status(200).json(result);
1042
- } else {
1043
- return res.status(500).json({
1044
- success: false,
1045
- message: "Failed to process the request.",
1046
- errors: result,
1047
- });
1048
- }
1049
- } catch (error) {
1050
- res.status(500).json({
1051
- success: false,
1052
- message: "Internal server error.",
1053
- errors: error || error.message,
1054
- });
1055
- }
1056
- });
1057
-
1058
-
1059
- /*******************
1060
- ┏┓┏━┓┏━━━┓┏━┓┏━┓┏━━┓┏┓┏━┓┏┓╋┏┓
1061
- ┃┃┃┏┛┃┏━┓┃┃┃┗┛┃┃┗┫┣┛┃┃┃┏┛┃┃╋┃┃
1062
- ┃┗┛┛╋┃┃╋┃┃┃┏┓┏┓┃╋┃┃╋┃┗┛┛╋┃┃╋┃┃
1063
- ┃┏┓┃╋┃┃╋┃┃┃┃┃┃┃┃╋┃┃╋┃┏┓┃╋┃┃╋┃┃
1064
- ┃┃┃┗┓┃┗━┛┃┃┃┃┃┃┃┏┫┣┓┃┃┃┗┓┃┗━┛┃
1065
- ┗┛┗━┛┗━━━┛┗┛┗┛┗┛┗━━┛┗┛┗━┛┗━━━┛
1066
- *********************/
1067
-
1068
-
1069
- async function iwaraDL(url) {
1070
- const browser = await puppeteer.launch({
1071
- headless: true,
1072
- args: ['--no-sandbox', '--disable-setuid-sandbox']
1073
- });
1074
- const page = await browser.newPage();
1075
- await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
1076
- await page.goto("https://fetchfile.me/download-iwara/", { waitUntil: 'domcontentloaded' });
1077
- await page.type('#url', url);
1078
- await page.click('#ring');
1079
- await page.waitForSelector('#result > div > div.youtube.col-md-7 > ul > li');
1080
-
1081
- const title = await page.$eval('#result > div > div.youtube.col-md-7 > h2', el => el.innerText);
1082
- const originalSource = await page.$eval('#mp4 > table > tbody > tr:nth-child(1) > td:nth-child(3) > a.dlw', el => el.href || null);
1083
- const high = await page.$eval('#mp4 > table > tbody > tr:nth-child(2) > td:nth-child(3) > a.dlw', el => el.href || null);
1084
- const standard = await page.$eval('#mp4 > table > tbody > tr:nth-child(3) > td:nth-child(3) > a.dlw', el => el.href || null);
1085
- const low = await page.$eval('#mp4 > table > tbody > tr:nth-child(4) > td:nth-child(3) > a.dlw', el => el.href || null);
1086
-
1087
- let ht = await page.content();
1088
- console.log("\n========================\n\n\n " + ht + " \n========================\n")
1089
- await browser.close();
1090
- return {
1091
- title,
1092
- originalSource: originalSource || 'Original source not available',
1093
- high: high || 'High quality not available',
1094
- standard: standard || 'Standard quality not available',
1095
- low: low || 'Low quality not available'
1096
- };
1097
- }
1098
-
1099
-
1100
- // Rute untuk menerima data melalui query string (GET)
1101
- app.get('/iwara/download', async (req, res) => {
1102
- const { url } = req.query;
1103
- if (!url) return res.status(400).json({ error: 'Parameter url is required' });
1104
- try {
1105
- const base64Result = await iwaraDL(url);
1106
- res.json(base64Result); // Mengirimkan buffer gambar sebagai respons
1107
- } catch (error) {
1108
- res.status(500).send(error);
1109
- }
1110
- });
1111
-
1112
- async function XnxxDown(inputUrl) {
1113
- const browser = await puppeteer.launch({
1114
- headless: true,
1115
- args: ['--no-sandbox', '--disable-setuid-sandbox']
1116
- });
1117
- const context = await browser.newPage()
1118
- const page = await context.newPage();
1119
- await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
1120
-
1121
- await page.goto(`https://www.locoloader.com/?url=${encodeURIComponent(inputUrl)}`, { waitUntil: 'domcontentloaded' });
1122
- await page.waitForSelector("#extraction > div > div.hl > h1 > a");
1123
-
1124
- const title = await page.$eval(
1125
- "#extraction > div > div.hl > h1 > a",
1126
- el => el.innerText.trim()
1127
- );
1128
-
1129
- const url = await page.$eval(
1130
- "#extraction > div > div.hl > h1 > a",
1131
- el => el.href
1132
- );
1133
-
1134
- const img = await page.$eval(
1135
- "#extraction > div > div.content-final-single__thumb-wrapper > div > div > img",
1136
- el => el.src
1137
- );
1138
-
1139
- const type = await page.$eval(
1140
- "#extraction > div > div:nth-child(3) > div.display-table-cell.linkInfo > div.icon-media",
1141
- el => el.innerText.trim()
1142
- );
1143
-
1144
- const downloadLink = await page.$eval(
1145
- "#extraction > div > div:nth-child(3) > div.display-table-cell.linkButtons > a.bt.dl",
1146
- el => el.href
1147
- );
1148
-
1149
- await browser.close();
1150
-
1151
- return { title, url, img, type, downloadLink };
1152
- }
1153
-
1154
- app.get('/xnxx/download', async (req, res) => {
1155
- const { url } = req.query;
1156
- if (!url) return res.status(400).json({ error: 'Parameter url is required' });
1157
- try {
1158
- const base64Result = await XnxxDown(url);
1159
- res.json(base64Result); // Mengirimkan buffer gambar sebagai respons
1160
- } catch (error) {
1161
- res.status(500).send(error);
1162
- }
1163
- });
1164
-
1165
- /*******************************/
1166
- // Fungsi untuk ping website
1167
- async function pingWebsite() {
1168
- const browser = await puppeteer.launch({
1169
- headless: true,
1170
- args: ['--no-sandbox', '--disable-setuid-sandbox']
1171
- });
1172
- const page = await browser.newPage();
1173
- await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
1174
- await page.goto('https://huggingface.co/spaces/ArashiCode/api');
1175
- console.log("Ping");
1176
- await browser.close();
1177
- }
1178
-
1179
- // Ping website setiap 5 jam
1180
- async function pingEvery5Hours() {
1181
- await pingWebsite();
1182
- setInterval(async () => {
1183
- await pingWebsite();
1184
- }, 5 * 60 * 60 * 1000); // 5 hours in milliseconds
1185
- }
1186
-
1187
- // Mulai ping
1188
- pingEvery5Hours();
1189
-
1190
- app.listen(PORT, () => {
1191
- console.log(`Server is running on port ${PORT}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1192
  });
 
1
+ import axios from 'axios';
2
+ import * as cheerio from 'cheerio';
3
+ import { createRequire } from 'module';
4
+ import os from 'os';
5
+ import express from 'express';
6
+ import { promisify, format } from 'util';
7
+ import { fileTypeFromBuffer } from 'file-type';
8
+ import ffmpeg from 'fluent-ffmpeg';
9
+ import nodeID3 from 'node-id3';
10
+ import ytdl from 'ytdl-core';
11
+ import FormData from 'form-data';
12
+ import fetch from 'node-fetch';
13
+ import mime from "mime-types";
14
+ const require = createRequire(import.meta.url);
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const { google } = require('googleapis');
18
+
19
+ const puppeteer = require('puppeteer-extra');
20
+ const StealthPlugin = require('puppeteer-extra-plugin-stealth');
21
+ puppeteer.use(StealthPlugin());
22
+
23
+
24
+ import { fileURLToPath } from 'url';
25
+ const PORT = process.env.PORT || 7860;
26
+ const app = express();
27
+ const readFileAsync = promisify(fs.readFile);
28
+
29
+ const tempDir = path.join(os.tmpdir(), "temp");
30
+ const fss = fs.promises;
31
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
32
+ // Membuat direktori sementara jika belum ada
33
+ (async () => {
34
+ if (!fs.existsSync(tempDir)) {
35
+ await fss.mkdir(tempDir, { recursive: true });
36
+ }
37
+ })();
38
+ const { exec } = require('child_process');
39
+ const writeFileAsync = promisify(fs.writeFile);
40
+ const execPromise = promisify(exec);
41
+ const youtube = google.youtube({ version: 'v3', auth: 'AIzaSyBPkpdJEGtAHebbaP3_CcA1_urfMFfeLLg' });
42
+ const bodyParser = require('body-parser');
43
+ app.use(bodyParser.json());
44
+
45
+
46
+
47
+ const tempDirBase = tempDir
48
+ const https = require('https');
49
+
50
+ const agent = new https.Agent({
51
+ rejectUnauthorized: false // Nonaktifkan verifikasi sertifikat
52
+ });
53
+
54
+ app.use('/temp', express.static(tempDir));
55
+ app.use(express.json());
56
+ app.use(express.raw({ type: '*/*', limit: '10mb' })); // Untuk menangani buffer dan data binary
57
+ app.use(express.urlencoded({ extended: true }));
58
+
59
+
60
+ app.all('/axios/:method/*', async (req, res) => {
61
+ const { method } = req.params;
62
+ const targetUrl = decodeURIComponent(req.params[0]); // Menangani URL setelah /:method/
63
+ const responseType = req.query.responseType || ''; // Menangani opsi responseType
64
+
65
+ let option = {
66
+ headers: {
67
+ ...req.headers, // Menyalin semua header dari permintaan asli
68
+ 'User-Agent': req.headers['user-agent'] || 'Mozilla/5.0 (Linux; Android 12; SM-S908B Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.58 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/357.0.0.23.115;] WhatsApp/1.2.3', // Menambahkan custom user-agent
69
+ },
70
+ httpsAgent: agent
71
+ };
72
+
73
+ if (responseType) {
74
+ option.responseType = responseType;
75
+ }
76
+
77
+ try {
78
+ let response;
79
+ if (method.toLowerCase() === 'get') {
80
+ response = await axios.get(targetUrl, option);
81
+ } else if (method.toLowerCase() === 'post') {
82
+ option.data = req.body;
83
+ response = await axios.post(targetUrl, req.body, option);
84
+ } else {
85
+ res.status(405).json({ error: 'Method not allowed' });
86
+ return;
87
+ }
88
+
89
+ // Mengambil Content-Type dari header respons
90
+ const mimeType = response.headers['content-type'];
91
+ const buffer = Buffer.from(response.data, 'binary');
92
+
93
+ res.status(response.status);
94
+ res.set(response.headers); // Set headers dari respons API
95
+
96
+ // Menangani respons berdasarkan Content-Type
97
+ if (mimeType && (mimeType.includes('text') || mimeType.includes('json') || mimeType.includes('html') || mimeType.includes('plain'))) {
98
+ // Kirim data sebagai teks
99
+ res.send(buffer.toString('utf-8'));
100
+ } else {
101
+ // Kirim file binary, termasuk PDF
102
+ res.setHeader('Content-Length', buffer.length);
103
+ res.send(buffer);
104
+ }
105
+ } catch (error) {
106
+ console.error('Error:', error.response ? error.response.data : error.message);
107
+
108
+ const statusCode = error.response ? error.response.status : 500;
109
+ const errorMessage = error.response ? error.response.data : error.message;
110
+
111
+ res.status(statusCode).json({
112
+ error: errorMessage
113
+ });
114
+ }
115
+ });
116
+
117
+ app.get("/", (req, res) => {
118
+ res.type("json");
119
+ const keluaran = {
120
+ success: true,
121
+ author: "Nex",
122
+ data: {
123
+ igdl: "/igdl",
124
+ twdl: "/twdl"
125
+ },
126
+ };
127
+ res.send(keluaran);
128
+ });
129
+
130
+ app.post("/eval", async (req, res) => {
131
+ const { code } = req.body;
132
+ const { responseType = "text" } = req.query;
133
+ let __dirname = path.dirname(fileURLToPath(import.meta.url));
134
+ let require = createRequire(__dirname);
135
+
136
+ let _return;
137
+ try {
138
+ _return = /await/i.test(code)
139
+ ? eval("(async() => { " + code + " })()")
140
+ : eval(code);
141
+ } catch (e) {
142
+ _return = e;
143
+ }
144
+
145
+ // Handle Buffer atau Base64
146
+ if (Buffer.isBuffer(_return) || typeof _return === "string" && _return.startsWith("data:")) {
147
+ const buffer = Buffer.isBuffer(_return)
148
+ ? _return
149
+ : Buffer.from(_return.split(",")[1], "base64");
150
+
151
+ const fileType = await fileTypeFromBuffer(buffer);
152
+ const mimeType = fileType ? fileType.mime : "application/octet-stream";
153
+ const ext = fileType ? fileType.ext : "bin";
154
+ const filename = `Nex - ${Date.now()}.${ext}`;
155
+
156
+ res.setHeader("Content-Type", mimeType);
157
+ res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
158
+ return res.send(buffer);
159
+ }
160
+
161
+ // Handle respon berdasarkan responseType
162
+ switch (responseType) {
163
+ case "json":
164
+ try {
165
+ const jsonFormatted = typeof _return === "string" ? JSON.parse(_return) : _return;
166
+ return res.json(format(jsonFormatted));
167
+ } catch (err) {
168
+ return res.json({ error: "Invalid JSON format", result: format(_return) });
169
+ }
170
+
171
+ case "file":
172
+ const filePath = path.join(__dirname, `Nex - ${Date.now()}.txt`);
173
+ fs.writeFileSync(filePath, _return.toString());
174
+ return res.download(filePath, () => fs.unlinkSync(filePath));
175
+
176
+ case "text":
177
+ default:
178
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
179
+ return res.send(_return.toString());
180
+ }
181
+ });
182
+
183
+
184
+
185
+
186
+
187
+ // Fungsi untuk menghasilkan IP acak
188
+ const generateRandomIP = () => {
189
+ const octet = () => Math.floor(Math.random() * 256);
190
+ return `${octet()}.${octet()}.${octet()}.${octet()}`;
191
+ };
192
+
193
+ // Fungsi untuk upload file
194
+ async function uploader(buffer) {
195
+ const { ext } = await fileTypeFromBuffer(buffer);
196
+ const bodyForm = new FormData();
197
+ bodyForm.append('file', buffer, `file.${ext}`);
198
+
199
+ const response = await fetch('https://aemt.me/api/upload.php', {
200
+ method: 'POST',
201
+ body: bodyForm,
202
+ });
203
+
204
+ return {
205
+ status: response.status,
206
+ creator: 'Nex',
207
+ result: await response.json(),
208
+ };
209
+ }
210
+
211
+ // Fungsi untuk mendapatkan URL thumbnail HD
212
+ async function getHDThumbnailUrl(videoId) {
213
+ try {
214
+ const response = await youtube.videos.list({ part: 'snippet', id: videoId });
215
+ return response.data.items[0].snippet.thumbnails.maxres.url;
216
+ } catch (error) {
217
+ console.error('Error fetching HD thumbnail URL:', error.message);
218
+ return null;
219
+ }
220
+ }
221
+
222
+ const getVideoDetailsWithApi = async (videoId) => {
223
+ const url = `https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId}&key=AIzaSyBPkpdJEGtAHebbaP3_CcA1_urfMFfeLLg`;
224
+
225
+ try {
226
+ const response = await axios.get(url);
227
+ const video = response.data.items[0];
228
+
229
+ const title = video.snippet.title;
230
+ const description = video.snippet.description;
231
+ const thumbnail = video.snippet.thumbnails.high.url;
232
+ const channelTitle = video.snippet.channelTitle;
233
+ const publishedAt = video.snippet.publishedAt;
234
+ const tags = video.snippet.tags;
235
+
236
+ const videoDetails = {
237
+ title: title,
238
+ description: description,
239
+ thumbnail: thumbnail,
240
+ channelTitle: channelTitle,
241
+ publishedAt: publishedAt,
242
+ tags: tags,
243
+ };
244
+
245
+ return videoDetails
246
+ } catch (error) {
247
+ console.error('An error occurred:', error);
248
+ }
249
+ };
250
+
251
+ // Fungsi untuk mendapatkan ID video dari URL
252
+ async function GetId(data) {
253
+ const regex = /(?:https?:\/\/)?(?:www\.)?(?:youtu(?:be\.com\/(?:watch\?(?:v=|vi=)|v\/|vi\/)|\.be\/|be\.com\/embed\/|be\.com\/shorts\/)|youtube\.com\/\?(?:v=|vi=))([\w-]{11})/;
254
+ const res = regex.exec(data);
255
+ if (res && res[1]) return res[1];
256
+ throw new Error("Please check the URL you have entered");
257
+ }
258
+
259
+ // Fungsi untuk menambahkan tag ID3 ke file audio
260
+ async function addAudioTags(media, title, artist, year, imagecover) {
261
+ try {
262
+ let audioBuffer;
263
+ if (typeof media === 'string') {
264
+ const response = await axios.get(media, { responseType: 'arraybuffer', maxContentLength: -1 });
265
+ audioBuffer = Buffer.from(response.data);
266
+ } else if (media instanceof Buffer) {
267
+ audioBuffer = media;
268
+ } else {
269
+ throw new Error('Media harus berupa URL string atau Buffer.');
270
+ }
271
+
272
+ const randomFilename = generateRandomName(10) + '.mp3';
273
+ const tmpFilePath = path.join(tempDir, randomFilename);
274
+ fs.writeFileSync(tmpFilePath, audioBuffer);
275
+
276
+ const tags = { title, artist, year };
277
+ if (typeof imagecover === 'string') {
278
+ const response = await axios.get(imagecover, { responseType: 'arraybuffer' });
279
+ const coverBuffer = Buffer.from(response.data);
280
+ tags.image = {
281
+ mime: 'image/jpeg',
282
+ type: { id: 3, name: 'Front Cover' },
283
+ description: 'Cover',
284
+ imageBuffer: coverBuffer
285
+ };
286
+ } else if (imagecover instanceof Buffer) {
287
+ tags.image = {
288
+ mime: 'image/jpeg',
289
+ type: { id: 3, name: 'Front Cover' },
290
+ description: 'Cover',
291
+ imageBuffer: imagecover
292
+ };
293
+ }
294
+
295
+ const success = nodeID3.write(tags, tmpFilePath);
296
+ console[success ? 'log' : 'error'](success ? 'Tag ID3 berhasil diubah!' : 'Gagal mengubah tag ID3.');
297
+
298
+ return { msg: `Audio berhasil diubah.`, path: `${tmpFilePath}` };
299
+ } catch (error) {
300
+ console.error('Terjadi kesalahan:', error);
301
+ throw new Error('Terjadi kesalahan saat mengubah audio.');
302
+ }
303
+ }
304
+
305
+ // Fungsi untuk menghasilkan nama acak
306
+ function generateRandomName(length) {
307
+ const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
308
+ let randomName = '';
309
+ for (let i = 0; i < length; i++) {
310
+ randomName += characters.charAt(Math.floor(Math.random() * characters.length));
311
+ }
312
+ return randomName;
313
+ }
314
+
315
+
316
+ async function fetchCobaltOnly(url, opts = {}) {
317
+ try {
318
+ const response = await axios.post('https://cobalt.siputzx.my.id/', { url, ...opts }, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } } );
319
+ return response.data;
320
+ } catch (error) {
321
+ if (error.response) {
322
+ const contentType = error.response.headers['content-type'];
323
+ if (contentType && contentType.includes('json')) {
324
+ throw error.response.data.message || 'An error occurred';
325
+ }
326
+ throw error.response.statusText;
327
+ }
328
+ throw error.message;
329
+ }
330
+ }
331
+
332
+
333
+
334
+ const servers = [
335
+ "https://cobalt.siputzx.my.id/",
336
+ "https://c.blahaj.ca/",
337
+ "https://api.co.waow.cat/",
338
+ "https://cobalt-api.kwiatekmiki.com",
339
+ "https://cobalt-backend.canine.tools/",
340
+ "https://cobalt.api.timelessnesses.me/",
341
+ "https://capi.3kh0.net"
342
+ ];
343
+
344
+ async function cobalt(config) {
345
+ try {
346
+ if (!(typeof config === "object")) {
347
+ throw new Error("Invalid config input, config must be a JSON object!");
348
+ }
349
+
350
+ config = {
351
+ url: config?.url || null,
352
+ videoQuality: config?.videoQuality || "720",
353
+ audioFormat: config?.audioFormat || "mp3",
354
+ audioBitrate: config?.audioBitrate || "128",
355
+ filenameStyle: config?.filenameStyle || "classic",
356
+ downloadMode: config?.downloadMode || "auto",
357
+ youtubeVideoCodec: config?.youtubeVideoCodec || "h264",
358
+ youtubeDubLang: config?.youtubeDubLang || "en",
359
+ alwaysProxy: config?.alwaysProxy || false,
360
+ disableMetadata: config?.disableMetadata || false,
361
+ tiktokFullAudio: config?.tiktokFullAudio || true,
362
+ tiktokH265: config?.tiktokH265 || true,
363
+ twitterGif: config?.twitterGif || true,
364
+ youtubeHLS: config?.youtubeHLS || false,
365
+ };
366
+
367
+ if (!config.url) {
368
+ throw new Error("Missing URL input!");
369
+ }
370
+
371
+ for (let i = 0; i < servers.length; i++) {
372
+ try {
373
+ console.log(`Trying server: ${servers[i]}`); // Log server yang dicoba
374
+ const response = await axios.post(servers[i], config, {
375
+ headers: {
376
+ accept: "application/json",
377
+ contentType: "application/json",
378
+ },
379
+ });
380
+
381
+ const data = response.data;
382
+ if (data.status === "error") {
383
+ throw new Error("Failed to fetch content from server.");
384
+ }
385
+
386
+ console.log(`Success with server: ${servers[i]}`); // Log server sukses
387
+ return {
388
+ success: true,
389
+ result: data,
390
+ };
391
+ } catch (error) {
392
+ if (i === servers.length - 1) {
393
+ // Jika sudah mencoba semua server
394
+ throw error;
395
+ }
396
+ console.warn(`Server ${servers[i]} failed. Trying next server...`); // Log server gagal
397
+ }
398
+ }
399
+ } catch (error) {
400
+ return {
401
+ success: false,
402
+ errors: error.message || error,
403
+ };
404
+ }
405
+ }
406
+
407
+ async function fetchSaveTubeAPI(opts = {}) {
408
+ const headers = {
409
+ Authority: 'cdn59.savetube.su',
410
+ 'Content-Type': 'application/json'
411
+ };
412
+ try {
413
+ const { data: info } = await axios.post(`https://${headers.Authority}/info`, opts, { headers });
414
+ opts.key = info.data.key;
415
+ const { data: result } = await axios.post(`https://${headers.Authority}/download`, opts, { headers });
416
+ return result;
417
+ } catch (error) {
418
+ return { success: false, message: error.response?.data?.message || error.message };
419
+ }
420
+ }
421
+
422
+
423
+ async function getAudioMP3Url(videoUrl) {
424
+ try {
425
+ const id_video = await GetId(videoUrl);
426
+ const infoVids = await getVideoDetailsWithApi(id_video);
427
+
428
+ const obj = {
429
+ type: 'audio',
430
+ quality: 128,
431
+ url: videoUrl
432
+ };
433
+ const payload = {
434
+ downloadType: obj.type !== 'video' ? 'audio' : 'video',
435
+ quality: obj.quality ? String(obj.quality) : obj.type !== 'video' ? '128' : '720',
436
+ url: obj.url
437
+ };
438
+
439
+ const video = await fetchSaveTubeAPI(payload);
440
+
441
+ const path_audio = path.join(tempDir, generateRandomName(10) + '.mp3');
442
+ const path_audio_edit = path_audio.replace('.mp3', '_edit.mp3');
443
+
444
+ // Download file audio
445
+ const headers = {
446
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36',
447
+ 'Referer': 'https://cobalt.tools/pustaka/'
448
+ };
449
+ const response = await axios.get(video.data.downloadUrl, { responseType: 'arraybuffer', headers });
450
+ fs.writeFileSync(path_audio, response.data);
451
+
452
+ // Periksa apakah file input valid
453
+ if (!fs.existsSync(path_audio)) {
454
+ throw new Error('File audio tidak ditemukan setelah diunduh.');
455
+ }
456
+ if (fs.statSync(path_audio).size === 0) {
457
+ throw new Error('File audio kosong atau rusak.');
458
+ }
459
+
460
+ // Debugging tambahan: coba cek format file
461
+ console.log(`File audio diunduh: ${path_audio}, size: ${fs.statSync(path_audio).size} bytes`);
462
+
463
+ // Tambahkan metadata ke file yang diunduh
464
+ await new Promise((resolve, reject) => {
465
+ ffmpeg(path_audio)
466
+ .outputOptions(['-acodec libmp3lame', '-ab 128k', '-ar 44100'])
467
+ .on('start', (commandLine) => {
468
+ console.log('FFmpeg command:', commandLine); // Log perintah FFmpeg
469
+ })
470
+ .on('stderr', (stderrLine) => {
471
+ console.error('FFmpeg stderr:', stderrLine); // Log error FFmpeg
472
+ })
473
+ .on('end', async () => {
474
+ try {
475
+ // Tambahkan metadata
476
+ const buffer = fs.readFileSync(path_audio_edit); // Ambil file hasil edit
477
+ const edited = await addAudioTags(buffer, infoVids.title, infoVids.channelTitle, 2024, infoVids.thumbnail);
478
+
479
+ // Ganti file lama dengan file yang sudah diedit
480
+ const buffer2 = fs.readFileSync(edited.path);
481
+ fs.writeFileSync(path_audio, buffer2);
482
+ fs.unlinkSync(path_audio_edit); // Hapus file sementara
483
+
484
+ resolve();
485
+ } catch (error) {
486
+ reject(error);
487
+ }
488
+ })
489
+ .on('error', (err) => {
490
+ console.error('FFmpeg conversion error:', err);
491
+ reject(err);
492
+ })
493
+ .save(path_audio_edit); // Simpan sementara dengan nama _edit.mp3
494
+ });
495
+
496
+ // Kembalikan hasil akhir
497
+ return {
498
+ status: 200,
499
+ title: infoVids.title,
500
+ result: {
501
+ fileName: video.filename || infoVids.title + ".mp3",
502
+ url_path: `https://${process.env.SPACE_HOST}/temp/${path.basename(path_audio)}`,
503
+ curl_path: `https://${process.env.SPACE_HOST}/temp/${path.basename(path_audio)}?download=1&filename=${infoVids.title}`,
504
+ path: path_audio
505
+ },
506
+ infoVids
507
+ };
508
+ } catch (error) {
509
+ console.error('Error:', error);
510
+ throw new Error('Failed to process audio URL');
511
+ }
512
+ }
513
+
514
+
515
+
516
+
517
+
518
+
519
+
520
+ app.get('/ytmp3', async (req, res) => {
521
+ try {
522
+ const { url } = req.query;
523
+ if (!url) return res.status(400).json({ error: 'Parameter url is required' });
524
+
525
+ let result = await getAudioMP3Url(url);
526
+ res.json(result);
527
+
528
+ // Menghapus file setelah 10 menit
529
+ try {
530
+ await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
531
+ await fss.unlink(result.result.path);
532
+ console.log(`File ${result.result.path} deleted.`);
533
+ } catch (error) {
534
+ console.error(`Error deleting file ${result.result.path}:`, error);
535
+ }
536
+ } catch (error) {
537
+ console.error('Error processing request:', error);
538
+ res.status(500).json({
539
+ error: 'Failed to process request\n' + error
540
+ });
541
+ }
542
+ });
543
+
544
+
545
+
546
+ async function fetchHtml(url) {
547
+ // Launch browser dengan mode headless
548
+ const browser = await puppeteer.launch({
549
+ headless: true,
550
+ args: ['--no-sandbox', '--disable-setuid-sandbox', '--incognito', '--single-process', '--no-sandbox', '--no-zygote', '--no-cache']
551
+ timeout: 60000 // Timeout untuk peluncuran browser
552
+ });
553
+
554
+ // Buat page baru
555
+ const page = await browser.newPage();
556
+
557
+ // Set User Agent untuk menghindari deteksi bot
558
+ //await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.3');
559
+
560
+ await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
561
+
562
+ // Navigasi ke URL yang diinginkan
563
+ //await page.goto(url);
564
+
565
+ await page.goto(url, { waitUntil: 'networkidle2' });
566
+
567
+ // Tunggu sampai page selesai loading
568
+ //await page.waitForNavigation({ waitUntil: 'networkidle2' });
569
+
570
+ // Ambil HTML dari page
571
+ const html = await page.content();
572
+
573
+ // Tutup browser
574
+ await browser.close();
575
+
576
+ // Return HTML
577
+ return html;
578
+ }
579
+
580
+ app.get('/html', async (req, res) => {
581
+ try {
582
+ const { url } = req.query;
583
+ if (!url) return res.status(400).json({ error: 'Parameter url is required' });
584
+ let result = await fetchHtml(url);
585
+ res.send(result);
586
+ } catch (error) {
587
+ console.error('Error processing request:', error);
588
+ res.status(500).json({
589
+ error: 'Failed to process request\n' + error
590
+ });
591
+ }
592
+ });
593
+
594
+
595
+ async function XnDl(url) {
596
+ const browser = await puppeteer.launch({
597
+ headless: true,
598
+ args: ['--no-sandbox', '--disable-setuid-sandbox', '--incognito', '--single-process', '--no-sandbox', '--no-zygote', '--no-cache']
599
+ timeout: 60000 // Timeout untuk peluncuran browser
600
+ });
601
+
602
+ try {
603
+ const context = await browser.createBrowserContext();
604
+ // Create a new page inside context.
605
+ const page = await context.newPage();
606
+ await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
607
+
608
+ await page.goto(url.replace("xnxx.com", "xnxxvideodownload.com"), {
609
+ waitUntil: 'domcontentloaded',
610
+ timeout: 60000 // Timeout untuk navigasi
611
+ });
612
+
613
+ await page.waitForNavigation({
614
+ waitUntil: 'networkidle0',
615
+ timeout: 60000 // Timeout untuk menunggu navigasi selesai
616
+ });
617
+
618
+ const data = await page.evaluate(() => {
619
+ const title = document.querySelector("body > main > section.e.j.d2.dsection > h2")?.textContent || '';
620
+ const thumbnail = document.querySelector("body > main > section.e.j.d2.dsection > div > div.thumbdiv > img")?.src || '';
621
+ const url = document.querySelector("body > main > section.e.j.d2.dsection > div > div.thumbdiv > a")?.href || '';
622
+
623
+ const table = document.getElementById('dtable')?.getElementsByTagName('table')[0];
624
+ const videoDownload = [];
625
+
626
+ if (table) {
627
+ for (let i = 0; i < table.rows.length; i++) {
628
+ const row = table.rows[i];
629
+ const rowData = {
630
+ quality: row.cells[0]?.innerText || '',
631
+ ext: row.cells[1]?.innerText || '',
632
+ url: row.cells[2]?.getElementsByTagName('a')[0]?.href || ''
633
+ };
634
+ videoDownload.push(rowData);
635
+ }
636
+ }
637
+
638
+ return { title, thumbnail, url, videoDownload };
639
+ });
640
+
641
+ return data;
642
+ } catch (error) {
643
+ console.error('Error:', error);
644
+ return null;
645
+ } finally {
646
+ await browser.close();
647
+ }
648
+ }
649
+
650
+
651
+ app.get('/xnxx', async (req, res) => {
652
+ try {
653
+ const { url } = req.query;
654
+ if (!url) return res.status(400).json({ error: 'Parameter url is required' });
655
+ let result = await XnDl(url);
656
+ res.send(result);
657
+ } catch (error) {
658
+ console.error('Error processing request:', error);
659
+ res.status(500).json({
660
+ error: 'Failed to process request\n' + error
661
+ });
662
+ }
663
+ });
664
+
665
+
666
+ /*
667
+ ┏┓┏━┓┏━━━┓┏━┓┏━┓┏━━┓┏┓┏━┓┏┓╋┏┓
668
+ ┃┃┃┏┛┃┏━┓┃┃┃┗┛┃┃┗┫┣┛┃┃┃┏┛┃┃╋┃┃
669
+ ┃┗┛┛╋┃┃╋┃┃┃┏┓┏┓┃╋┃┃╋┃┗┛┛╋┃┃╋┃┃
670
+ ┃┏┓┃╋┃┃╋┃┃┃┃┃┃┃┃╋┃┃╋┃┏┓┃╋┃┃╋┃┃
671
+ ┃┃┃┗┓┃┗━┛┃┃┃┃┃┃┃┏┫┣┓┃┃┃┗┓┃┗━┛┃
672
+ ┗┛┗━┛┗━━━┛┗┛┗┛┗┛┗━━┛┗┛┗━┛┗━━━┛
673
+ */
674
+
675
+ function generateRandomID(length = 8) {
676
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
677
+ let result = '';
678
+ for (let i = 0; i < length; i++) {
679
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
680
+ }
681
+ return result;
682
+ }
683
+
684
+ async function komiku_download(url) {
685
+ const instanceID = generateRandomID();
686
+ const tempDir = path.join(tempDirBase, instanceID);
687
+ await fss.mkdir(tempDir);
688
+
689
+ // Extracting the title from the URL
690
+ const title = url.split('/').filter(part => part).pop();
691
+
692
+ try {
693
+ const response = await axios.get(url);
694
+ const html = response.data;
695
+ const $ = cheerio.load(html);
696
+ const imgList = [];
697
+
698
+ $('#Baca_Komik img').each((index, element) => {
699
+ const src = $(element).attr('src');
700
+ imgList.push({ path: src });
701
+ });
702
+
703
+ await processImages(imgList, tempDir, instanceID);
704
+ const pdfPath = await createPDF(instanceID, tempDir);
705
+
706
+ console.log(`PDF berhasil dibuat: ${pdfPath}`);
707
+ return { path: pdfPath, title: title, url: `https://${process.env.SPACE_HOST}/temp/${path.basename(pdfPathq)}` };
708
+ } catch (error) {
709
+ console.log(error);
710
+ throw error;
711
+ } finally {
712
+ await fss.rmdir(tempDir, { recursive: true });
713
+ }
714
+ }
715
+
716
+ async function downloadImage(image, tempDir, instanceID) {
717
+ const response = await axios.get(image.path, { responseType: 'arraybuffer' });
718
+ const imagePath = path.join(tempDir, `image_${instanceID}_${Date.now()}_${Math.floor(Math.random() * 1000)}.jpg`);
719
+ await writeFileAsync(imagePath, response.data);
720
+
721
+ const imageHeight = await getImageHeight(imagePath);
722
+ const newHeight = Math.floor(imageHeight * 0.7);
723
+ const command = `convert ${imagePath} -resize 720x${newHeight}! -quality 75 -background white -gravity center -extent 720x${newHeight} ${imagePath}`;
724
+ await execPromise(command);
725
+
726
+ return imagePath;
727
+ }
728
+
729
+ async function getImageHeight(imagePath) {
730
+ const { stdout } = await execPromise(`identify -format "%h" ${imagePath}`);
731
+ return parseInt(stdout.trim());
732
+ }
733
+
734
+ async function processImages(imgList, tempDir, instanceID) {
735
+ const maxImagesPerPage = 10; // Maksimal 10 gambar per halaman
736
+ let partIndex = 0;
737
+ let partImages = [];
738
+
739
+ for (let i = 0; i < imgList.length; i++) {
740
+ const imagePath = await downloadImage(imgList[i], tempDir, instanceID);
741
+ partImages.push(imagePath);
742
+
743
+ if (partImages.length >= maxImagesPerPage) {
744
+ await combineAndSave(partImages, partIndex, tempDir, instanceID);
745
+ partImages = [];
746
+ partIndex++;
747
+ }
748
+ }
749
+
750
+ // Jika masih ada gambar yang belum diproses
751
+ if (partImages.length > 0) {
752
+ await combineAndSave(partImages, partIndex, tempDir, instanceID);
753
+ }
754
+ }
755
+
756
+ async function combineAndSave(imagePaths, partIndex, tempDir, instanceID) {
757
+ const combinedImagePath = path.join(tempDir, `combined_part_${instanceID}_${partIndex}.jpg`);
758
+ const command = `convert ${imagePaths.join(' ')} -append -quality 75 ${combinedImagePath}`;
759
+ await execPromise(command);
760
+
761
+ imagePaths.forEach(fs.unlinkSync);
762
+
763
+ return combinedImagePath;
764
+ }
765
+
766
+ async function createPDF(instanceID, tempDir) {
767
+ const combinedParts = fs.readdirSync(tempDir).filter(file => file.startsWith(`combined_part_${instanceID}_`));
768
+ const combinedImagesPath = combinedParts.map(file => path.join(tempDir, file)).join(' ');
769
+
770
+ const pdfPath = path.join(tempDir, `${instanceID}.pdf`);
771
+ const createPDFCommand = `convert ${combinedImagesPath} ${pdfPath}`;
772
+ await execPromise(createPDFCommand);
773
+
774
+ return pdfPath;
775
+ }
776
+
777
+ app.get('/komiku/download', async (req, res) => {
778
+ try {
779
+ const { url } = req.query;
780
+ if (!url) return res.status(400).json({ error: 'Parameter url is required' });
781
+
782
+ let result = await komiku_download(url);
783
+ res.json(result);
784
+
785
+ // Menghapus file setelah 10 menit
786
+ try {
787
+ await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
788
+ await fss.unlink(result.path);
789
+ console.log(`File ${result.path} deleted.`);
790
+ } catch (error) {
791
+ console.error(`Error deleting file ${result.path}:`, error);
792
+ }
793
+ } catch (error) {
794
+ console.error('Error processing request:', error);
795
+ res.status(500).json({
796
+ error: 'Failed to process request\n' + error
797
+ });
798
+ }
799
+ });
800
+ /*
801
+ V2 V2 V2 V2
802
+ */
803
+
804
+ async function komiku_downloadV2(url) {
805
+ const instanceID = generateRandomID();
806
+ const tempDir = path.join(tempDirBase, instanceID);
807
+ await fss.mkdir(tempDir);
808
+
809
+ // Extracting the title from the URL
810
+ const title = url.split('/').filter(part => part).pop();
811
+
812
+ let browser;
813
+ try {
814
+ browser = await puppeteer.launch({
815
+ headless: true,
816
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
817
+ });
818
+ const page = await browser.newPage();
819
+ await page.goto(url, { waitUntil: 'networkidle2' });
820
+
821
+ // Extracting images from the page
822
+ const imgList = await page.evaluate(() => {
823
+ return Array.from(document.querySelectorAll('#Baca_Komik img')).map(img => img.src);
824
+ });
825
+
826
+ const images = imgList.map(src => ({ path: src }));
827
+
828
+ await processImagesV2(images, tempDir, instanceID);
829
+ const pdfPath = await createPDFV2(instanceID, tempDir);
830
+
831
+ console.log(`PDF berhasil dibuat: ${pdfPath}`);
832
+ return { path: pdfPath, title: title, url: `https://${process.env.SPACE_HOST}/temp/${path.basename(pdfPath)}` };
833
+ } catch (error) {
834
+ console.log(error);
835
+ throw error;
836
+ } finally {
837
+ if (browser) {
838
+ await browser.close();
839
+ }
840
+ await fss.rmdir(tempDir, { recursive: true });
841
+ }
842
+ }
843
+
844
+ async function downloadImageV2(image, tempDir, instanceID) {
845
+ const response = await puppeteer.download(image.path, { responseType: 'arraybuffer' });
846
+ const imagePath = path.join(tempDir, `image_${instanceID}_${Date.now()}_${Math.floor(Math.random() * 1000)}.jpg`);
847
+ await writeFileAsync(imagePath, response);
848
+
849
+ const imageHeight = await getImageHeightV2(imagePath);
850
+ const newHeight = Math.floor(imageHeight * 0.7);
851
+ const command = `convert ${imagePath} -resize 720x${newHeight}! -quality 75 -background white -gravity center -extent 720x${newHeight} ${imagePath}`;
852
+ await execPromise(command);
853
+
854
+ return imagePath;
855
+ }
856
+
857
+ async function getImageHeightV2(imagePath) {
858
+ const { stdout } = await execPromise(`identify -format "%h" ${imagePath}`);
859
+ return parseInt(stdout.trim());
860
+ }
861
+
862
+ async function processImagesV2(imgList, tempDir, instanceID) {
863
+ const maxImagesPerPage = 10; // Maksimal 10 gambar per halaman
864
+ let partIndex = 0;
865
+ let partImages = [];
866
+
867
+ for (let i = 0; i < imgList.length; i++) {
868
+ const imagePath = await downloadImageV2(imgList[i], tempDir, instanceID);
869
+ partImages.push(imagePath);
870
+
871
+ if (partImages.length >= maxImagesPerPage) {
872
+ await combineAndSaveV2(partImages, partIndex, tempDir, instanceID);
873
+ partImages = [];
874
+ partIndex++;
875
+ }
876
+ }
877
+
878
+ // Jika masih ada gambar yang belum diproses
879
+ if (partImages.length > 0) {
880
+ await combineAndSaveV2(partImages, partIndex, tempDir, instanceID);
881
+ }
882
+ }
883
+
884
+ async function combineAndSaveV2(imagePaths, partIndex, tempDir, instanceID) {
885
+ const combinedImagePath = path.join(tempDir, `combined_part_${instanceID}_${partIndex}.jpg`);
886
+ const command = `convert ${imagePaths.join(' ')} -append -quality 75 ${combinedImagePath}`;
887
+ await execPromise(command);
888
+
889
+ imagePaths.forEach(fs.unlinkSync);
890
+
891
+ return combinedImagePath;
892
+ }
893
+
894
+ async function createPDFV2(instanceID, tempDir) {
895
+ const combinedParts = fs.readdirSync(tempDir).filter(file => file.startsWith(`combined_part_${instanceID}_`));
896
+ const combinedImagesPath = combinedParts.map(file => path.join(tempDir, file)).join(' ');
897
+
898
+ const pdfPath = path.join(tempDir, `${instanceID}.pdf`);
899
+ const createPDFCommand = `convert ${combinedImagesPath} ${pdfPath}`;
900
+ await execPromise(createPDFCommand);
901
+
902
+ return pdfPath;
903
+ }
904
+
905
+
906
+ app.get('/komiku/downloadV2', async (req, res) => {
907
+ try {
908
+ const { url } = req.query;
909
+ if (!url) return res.status(400).json({ error: 'Parameter url is required' });
910
+ let result = await komiku_downloadV2(url);
911
+ res.json(result);
912
+
913
+ // Menghapus file setelah 10 menit
914
+ try {
915
+ await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
916
+ await fss.unlink(result.path);
917
+ console.log(`File ${result.path} deleted.`);
918
+ } catch (error) {
919
+ console.error(`Error deleting file ${result.path}:`, error);
920
+ }
921
+ } catch (error) {
922
+ console.error('Error processing request:', error);
923
+ res.status(500).json({
924
+ error: 'Failed to process request\n' + error
925
+ });
926
+ }
927
+ });
928
+ /***********/
929
+
930
+ async function getLatestKomik(page) {
931
+ const url = `https://api.komiku.id/manga/page/${page}/`;
932
+ const headers = {
933
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36',
934
+ 'Referer': 'https://komiku.id/pustaka/'
935
+ };
936
+
937
+ try {
938
+ const response = await axios.get(url, { headers });
939
+ const $ = cheerio.load(response.data);
940
+ const mangaArray = [];
941
+
942
+ // Scraping data
943
+ $('.bge').each((index, element) => {
944
+ const title = $(element).find('.kan h3').text().trim();
945
+ const link_komik = $(element).find('.bgei a').attr('href');
946
+ const imgSrc = $(element).find('.bgei img').attr('src');
947
+ const type = $(element).find('.tpe1_inf b').text().trim();
948
+ const type2 = $(element).find('.tpe1_inf').text().trim();
949
+ const description = $(element).find('.kan p').text().trim();
950
+ const readersInfo = $(element).find('.judul2').text().trim();
951
+ const latestChapter = "https://komiku.id" + $(element).find('.new1:last-child a').attr('href');
952
+
953
+ mangaArray.push({
954
+ title,
955
+ link_komik,
956
+ imgSrc,
957
+ type,
958
+ type2,
959
+ description,
960
+ readersInfo,
961
+ latestChapter
962
+ });
963
+ });
964
+
965
+ return mangaArray;
966
+ } catch (error) {
967
+ console.error('Error fetching the URL', error);
968
+ throw error;
969
+ }
970
+ }
971
+
972
+ async function GetKomik(url) {
973
+ try {
974
+ const response = await axios.get(url);
975
+ const $ = cheerio.load(response.data);
976
+
977
+ const cover = $('#Informasi > div > img').attr('src');
978
+ const judul = $('#Informasi > table > tbody > tr:nth-child(1) > td:nth-child(2)').text().trim();
979
+ const jenis = $('#Informasi > table > tbody > tr:nth-child(3) > td:nth-child(2) > b').text().trim();
980
+ const konsepCerita = $('#Informasi > table > tbody > tr:nth-child(4) > td:nth-child(2)').text().trim();
981
+ const author = $('#Informasi > table > tbody > tr:nth-child(5) > td:nth-child(2)').text().trim();
982
+ const status = $('#Informasi > table > tbody > tr:nth-child(6) > td:nth-child(2)').text().trim();
983
+ const sinopsis = $('#Judul > p.desc').text().trim();
984
+
985
+ const genreElements = $('#Informasi > ul > li').map((i, el) => $(el).text().trim()).get();
986
+
987
+ const chapterElements = $('#daftarChapter > tr').map((i, el) => {
988
+ if (i === 0) {
989
+ return null;
990
+ }
991
+ return {
992
+ judulSeries: $(el).find('td.judulseries > a').text().trim(),
993
+ tanggalUpdate: $(el).find('td.tanggalseries').text().trim(),
994
+ url: "https://komiku.id" + $(el).find('td.judulseries > a').attr('href')
995
+ };
996
+ }).get().filter(chapter => chapter !== null);
997
+
998
+ const mangaInfo = {
999
+ cover,
1000
+ judul,
1001
+ sinopsis,
1002
+ jenis,
1003
+ konsepCerita,
1004
+ author,
1005
+ status,
1006
+ genres: genreElements,
1007
+ chapters: chapterElements
1008
+ };
1009
+
1010
+ return mangaInfo;
1011
+ } catch (error) {
1012
+ console.error('Error fetching the URL', error);
1013
+ throw error;
1014
+ }
1015
+ }
1016
+
1017
+
1018
+ app.get('/komiku/latest', async (req, res) => {
1019
+ try {
1020
+ const { page } = req.query;
1021
+ if (!page) return res.status(400).json({ error: 'Parameter page is required' });
1022
+
1023
+ let result = await getLatestKomik(page);
1024
+ res.json(result);
1025
+ } catch (error) {
1026
+ console.error('Error processing request:', error);
1027
+ res.status(500).json({
1028
+ error: 'Failed to process request\n' + error
1029
+ });
1030
+ }
1031
+ });
1032
+
1033
+ app.get('/komiku', async (req, res) => {
1034
+ try {
1035
+ const { url } = req.query;
1036
+ if (!url) return res.status(400).json({ error: 'Parameter url is required' });
1037
+
1038
+ let result = await GetKomik(url);
1039
+ res.json(result);
1040
+ } catch (error) {
1041
+ console.error('Error processing request:', error);
1042
+ res.status(500).json({
1043
+ error: 'Failed to process request\n' + error
1044
+ });
1045
+ }
1046
+ });
1047
+
1048
+
1049
+ app.post("/cobalt", async (req, res) => {
1050
+ const config = req.body;
1051
+ try {
1052
+ if (!config.url) {
1053
+ return res.status(400).json({
1054
+ success: false,
1055
+ message: "Missing 'url' in the request body.",
1056
+ });
1057
+ }
1058
+ const result = await cobalt(config);
1059
+ if (result.success) {
1060
+ return res.status(200).json(result);
1061
+ } else {
1062
+ return res.status(500).json({
1063
+ success: false,
1064
+ message: "Failed to process the request.",
1065
+ errors: result,
1066
+ });
1067
+ }
1068
+ } catch (error) {
1069
+ res.status(500).json({
1070
+ success: false,
1071
+ message: "Internal server error.",
1072
+ errors: error || error.message,
1073
+ });
1074
+ }
1075
+ });
1076
+
1077
+
1078
+ /*******************
1079
+ ┏┓┏━┓┏━━━┓┏━┓┏━┓┏━━┓┏┓┏━┓┏┓╋┏┓
1080
+ ┃┃┃┏┛┃┏━┓┃┃┃┗┛┃┃┗┫┣┛┃┃┃┏┛┃┃╋┃┃
1081
+ ┃┗┛┛╋┃┃╋┃┃┃┏┓┏┓┃╋┃┃╋┃┗┛┛╋┃┃╋┃┃
1082
+ ┃┏┓┃╋┃┃╋┃┃┃┃┃┃┃┃╋┃┃╋┃┏┓┃╋┃┃╋┃┃
1083
+ ┃┃┃┗┓┃┗━┛┃┃┃┃┃┃┃┏┫┣┓┃┃┃┗┓┃┗━┛┃
1084
+ ┗┛┗━┛┗━━━┛┗┛┗┛┗┛┗━━┛┗┛┗━┛┗━━━┛
1085
+ *********************/
1086
+
1087
+
1088
+ async function iwaraDL(url) {
1089
+ const browser = await puppeteer.launch({
1090
+ headless: true,
1091
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
1092
+ });
1093
+ const page = await browser.newPage();
1094
+ await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
1095
+ await page.goto("https://fetchfile.me/download-iwara/", { waitUntil: 'domcontentloaded' });
1096
+ await page.type('#url', url);
1097
+ await page.click('#ring');
1098
+ await page.waitForSelector('#result > div > div.youtube.col-md-7 > ul > li');
1099
+
1100
+ const title = await page.$eval('#result > div > div.youtube.col-md-7 > h2', el => el.innerText);
1101
+ const originalSource = await page.$eval('#mp4 > table > tbody > tr:nth-child(1) > td:nth-child(3) > a.dlw', el => el.href || null);
1102
+ const high = await page.$eval('#mp4 > table > tbody > tr:nth-child(2) > td:nth-child(3) > a.dlw', el => el.href || null);
1103
+ const standard = await page.$eval('#mp4 > table > tbody > tr:nth-child(3) > td:nth-child(3) > a.dlw', el => el.href || null);
1104
+ const low = await page.$eval('#mp4 > table > tbody > tr:nth-child(4) > td:nth-child(3) > a.dlw', el => el.href || null);
1105
+
1106
+ let ht = await page.content();
1107
+ console.log("\n========================\n\n\n " + ht + " \n========================\n")
1108
+ await browser.close();
1109
+ return {
1110
+ title,
1111
+ originalSource: originalSource || 'Original source not available',
1112
+ high: high || 'High quality not available',
1113
+ standard: standard || 'Standard quality not available',
1114
+ low: low || 'Low quality not available'
1115
+ };
1116
+ }
1117
+
1118
+
1119
+ // Rute untuk menerima data melalui query string (GET)
1120
+ app.get('/iwara/download', async (req, res) => {
1121
+ const { url } = req.query;
1122
+ if (!url) return res.status(400).json({ error: 'Parameter url is required' });
1123
+ try {
1124
+ const base64Result = await iwaraDL(url);
1125
+ res.json(base64Result); // Mengirimkan buffer gambar sebagai respons
1126
+ } catch (error) {
1127
+ res.status(500).send(error);
1128
+ }
1129
+ });
1130
+
1131
+ async function XnxxDown(inputUrl) {
1132
+ const browser = await puppeteer.launch({
1133
+ headless: true,
1134
+ args: ['--no-sandbox', '--disable-setuid-sandbox', '--incognito', '--single-process', '--no-sandbox', '--no-zygote', '--no-cache']
1135
+ });
1136
+ const page = await browser.newPage();
1137
+ await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
1138
+
1139
+ await page.goto(`https://www.locoloader.com/?url=${encodeURIComponent(inputUrl)}`, { waitUntil: 'domcontentloaded' });
1140
+ await page.waitForSelector("#extraction > div > div.hl > h1 > a");
1141
+
1142
+ const title = await page.$eval(
1143
+ "#extraction > div > div.hl > h1 > a",
1144
+ el => el.innerText.trim()
1145
+ );
1146
+
1147
+ const url = await page.$eval(
1148
+ "#extraction > div > div.hl > h1 > a",
1149
+ el => el.href
1150
+ );
1151
+
1152
+ const img = await page.$eval(
1153
+ "#extraction > div > div.content-final-single__thumb-wrapper > div > div > img",
1154
+ el => el.src
1155
+ );
1156
+
1157
+ const type = await page.$eval(
1158
+ "#extraction > div > div:nth-child(3) > div.display-table-cell.linkInfo > div.icon-media",
1159
+ el => el.innerText.trim()
1160
+ );
1161
+
1162
+ const downloadLink = await page.$eval(
1163
+ "#extraction > div > div:nth-child(3) > div.display-table-cell.linkButtons > a.bt.dl",
1164
+ el => el.href
1165
+ );
1166
+
1167
+ await browser.close();
1168
+
1169
+ return { title, url, img, type, downloadLink };
1170
+ }
1171
+
1172
+ app.get('/xnxx/download', async (req, res) => {
1173
+ const { url } = req.query;
1174
+ if (!url) return res.status(400).json({ error: 'Parameter url is required' });
1175
+ try {
1176
+ const base64Result = await XnxxDown(url);
1177
+ res.json(base64Result); // Mengirimkan buffer gambar sebagai respons
1178
+ } catch (error) {
1179
+ res.status(500).send(error);
1180
+ }
1181
+ });
1182
+
1183
+ /*******************************/
1184
+ // Fungsi untuk ping website
1185
+ async function pingWebsite() {
1186
+ const browser = await puppeteer.launch({
1187
+ headless: true,
1188
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
1189
+ });
1190
+ const page = await browser.newPage();
1191
+ await page.setUserAgent("Mozilla/5.0 (Linux; Android 10; SM-G965U Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.141 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.32.61;]");
1192
+ await page.goto('https://huggingface.co/spaces/ArashiCode/api');
1193
+ console.log("Ping");
1194
+ await browser.close();
1195
+ }
1196
+
1197
+ // Ping website setiap 5 jam
1198
+ async function pingEvery5Hours() {
1199
+ await pingWebsite();
1200
+ setInterval(async () => {
1201
+ await pingWebsite();
1202
+ }, 5 * 60 * 60 * 1000); // 5 hours in milliseconds
1203
+ }
1204
+
1205
+ // Mulai ping
1206
+ pingEvery5Hours();
1207
+
1208
+ app.listen(PORT, () => {
1209
+ console.log(`Server is running on port ${PORT}`);
1210
  });