Spaces:
Paused
Paused
| import axios from 'axios'; | |
| import * as cheerio from 'cheerio'; | |
| import { createRequire } from 'module'; | |
| import os from 'os'; | |
| import express from 'express'; | |
| import { promisify, format } from 'util'; | |
| import { fileTypeFromBuffer } from 'file-type'; | |
| import ffmpeg from 'fluent-ffmpeg'; | |
| import nodeID3 from 'node-id3'; | |
| import ytdl from 'ytdl-core'; | |
| import FormData from 'form-data'; | |
| import fetch from 'node-fetch'; | |
| import mime from "mime-types"; | |
| const require = createRequire(import.meta.url); | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const { google } = require('googleapis'); | |
| const puppeteer = require('puppeteer-extra'); | |
| const StealthPlugin = require('puppeteer-extra-plugin-stealth'); | |
| puppeteer.use(StealthPlugin()); | |
| import { fileURLToPath } from 'url'; | |
| const PORT = process.env.PORT || 7860; | |
| const app = express(); | |
| const readFileAsync = promisify(fs.readFile); | |
| const tempDir = path.join(os.tmpdir(), "temp"); | |
| const fss = fs.promises; | |
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | |
| // Membuat direktori sementara jika belum ada | |
| (async () => { | |
| if (!fs.existsSync(tempDir)) { | |
| await fss.mkdir(tempDir, { recursive: true }); | |
| } | |
| })(); | |
| const { exec } = require('child_process'); | |
| const writeFileAsync = promisify(fs.writeFile); | |
| const execPromise = promisify(exec); | |
| const youtube = google.youtube({ version: 'v3', auth: 'AIzaSyBPkpdJEGtAHebbaP3_CcA1_urfMFfeLLg' }); | |
| const bodyParser = require('body-parser'); | |
| app.use(bodyParser.json()); | |
| const tempDirBase = tempDir | |
| const https = require('https'); | |
| const agent = new https.Agent({ | |
| rejectUnauthorized: false // Nonaktifkan verifikasi sertifikat | |
| }); | |
| app.use('/temp', express.static(tempDir)); | |
| app.use(express.json()); | |
| app.use(express.raw({ type: '*/*', limit: '10mb' })); // Untuk menangani buffer dan data binary | |
| app.use(express.urlencoded({ extended: true })); | |
| app.all('/axios/:method/*', async (req, res) => { | |
| const { method } = req.params; | |
| const targetUrl = decodeURIComponent(req.params[0]); // Menangani URL setelah /:method/ | |
| const responseType = req.query.responseType || ''; // Menangani opsi responseType | |
| let option = { | |
| headers: { | |
| ...req.headers, // Menyalin semua header dari permintaan asli | |
| '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 | |
| }, | |
| httpsAgent: agent | |
| }; | |
| if (responseType) { | |
| option.responseType = responseType; | |
| } | |
| try { | |
| let response; | |
| if (method.toLowerCase() === 'get') { | |
| response = await axios.get(targetUrl, option); | |
| } else if (method.toLowerCase() === 'post') { | |
| option.data = req.body; | |
| response = await axios.post(targetUrl, req.body, option); | |
| } else { | |
| res.status(405).json({ error: 'Method not allowed' }); | |
| return; | |
| } | |
| // Mengambil Content-Type dari header respons | |
| const mimeType = response.headers['content-type']; | |
| const buffer = Buffer.from(response.data, 'binary'); | |
| res.status(response.status); | |
| res.set(response.headers); // Set headers dari respons API | |
| // Menangani respons berdasarkan Content-Type | |
| if (mimeType && (mimeType.includes('text') || mimeType.includes('json') || mimeType.includes('html') || mimeType.includes('plain'))) { | |
| // Kirim data sebagai teks | |
| res.send(buffer.toString('utf-8')); | |
| } else { | |
| // Kirim file binary, termasuk PDF | |
| res.setHeader('Content-Length', buffer.length); | |
| res.send(buffer); | |
| } | |
| } catch (error) { | |
| console.error('Error:', error.response ? error.response.data : error.message); | |
| const statusCode = error.response ? error.response.status : 500; | |
| const errorMessage = error.response ? error.response.data : error.message; | |
| res.status(statusCode).json({ | |
| error: errorMessage | |
| }); | |
| } | |
| }); | |
| app.get("/", (req, res) => { | |
| res.type("json"); | |
| const keluaran = { | |
| success: true, | |
| author: "Nex", | |
| data: { | |
| igdl: "/igdl", | |
| twdl: "/twdl" | |
| }, | |
| }; | |
| res.send(keluaran); | |
| }); | |
| app.post("/eval", async (req, res) => { | |
| const { code } = req.body; | |
| const { responseType = "text" } = req.query; | |
| let __dirname = path.dirname(fileURLToPath(import.meta.url)); | |
| let require = createRequire(__dirname); | |
| let _return; | |
| try { | |
| _return = /await/i.test(code) | |
| ? eval("(async() => { " + code + " })()") | |
| : eval(code); | |
| } catch (e) { | |
| _return = e; | |
| } | |
| // Handle Buffer atau Base64 | |
| if (Buffer.isBuffer(_return) || typeof _return === "string" && _return.startsWith("data:")) { | |
| const buffer = Buffer.isBuffer(_return) | |
| ? _return | |
| : Buffer.from(_return.split(",")[1], "base64"); | |
| const fileType = await fileTypeFromBuffer(buffer); | |
| const mimeType = fileType ? fileType.mime : "application/octet-stream"; | |
| const ext = fileType ? fileType.ext : "bin"; | |
| const filename = `Nex - ${Date.now()}.${ext}`; | |
| res.setHeader("Content-Type", mimeType); | |
| res.setHeader("Content-Disposition", `attachment; filename="${filename}"`); | |
| return res.send(buffer); | |
| } | |
| // Handle respon berdasarkan responseType | |
| switch (responseType) { | |
| case "json": | |
| try { | |
| const jsonFormatted = typeof _return === "string" ? JSON.parse(_return) : _return; | |
| return res.json(format(jsonFormatted)); | |
| } catch (err) { | |
| return res.json({ error: "Invalid JSON format", result: format(_return) }); | |
| } | |
| case "file": | |
| const filePath = path.join(__dirname, `Nex - ${Date.now()}.txt`); | |
| fs.writeFileSync(filePath, _return.toString()); | |
| return res.download(filePath, () => fs.unlinkSync(filePath)); | |
| case "text": | |
| default: | |
| res.setHeader("Content-Type", "text/plain; charset=utf-8"); | |
| return res.send(_return.toString()); | |
| } | |
| }); | |
| // Fungsi untuk menghasilkan IP acak | |
| const generateRandomIP = () => { | |
| const octet = () => Math.floor(Math.random() * 256); | |
| return `${octet()}.${octet()}.${octet()}.${octet()}`; | |
| }; | |
| // Fungsi untuk upload file | |
| async function uploader(buffer) { | |
| const { ext } = await fileTypeFromBuffer(buffer); | |
| const bodyForm = new FormData(); | |
| bodyForm.append('file', buffer, `file.${ext}`); | |
| const response = await fetch('https://aemt.me/api/upload.php', { | |
| method: 'POST', | |
| body: bodyForm, | |
| }); | |
| return { | |
| status: response.status, | |
| creator: 'Nex', | |
| result: await response.json(), | |
| }; | |
| } | |
| // Fungsi untuk mendapatkan URL thumbnail HD | |
| async function getHDThumbnailUrl(videoId) { | |
| try { | |
| const response = await youtube.videos.list({ part: 'snippet', id: videoId }); | |
| return response.data.items[0].snippet.thumbnails.maxres.url; | |
| } catch (error) { | |
| console.error('Error fetching HD thumbnail URL:', error.message); | |
| return null; | |
| } | |
| } | |
| const getVideoDetailsWithApi = async (videoId) => { | |
| const url = `https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId}&key=AIzaSyBPkpdJEGtAHebbaP3_CcA1_urfMFfeLLg`; | |
| try { | |
| const response = await axios.get(url); | |
| const video = response.data.items[0]; | |
| const title = video.snippet.title; | |
| const description = video.snippet.description; | |
| const thumbnail = video.snippet.thumbnails.high.url; | |
| const channelTitle = video.snippet.channelTitle; | |
| const publishedAt = video.snippet.publishedAt; | |
| const tags = video.snippet.tags; | |
| const videoDetails = { | |
| title: title, | |
| description: description, | |
| thumbnail: thumbnail, | |
| channelTitle: channelTitle, | |
| publishedAt: publishedAt, | |
| tags: tags, | |
| }; | |
| return videoDetails | |
| } catch (error) { | |
| console.error('An error occurred:', error); | |
| } | |
| }; | |
| // Fungsi untuk mendapatkan ID video dari URL | |
| async function GetId(data) { | |
| 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})/; | |
| const res = regex.exec(data); | |
| if (res && res[1]) return res[1]; | |
| throw new Error("Please check the URL you have entered"); | |
| } | |
| // Fungsi untuk menambahkan tag ID3 ke file audio | |
| async function addAudioTags(media, title, artist, year, imagecover) { | |
| try { | |
| let audioBuffer; | |
| if (typeof media === 'string') { | |
| const response = await axios.get(media, { responseType: 'arraybuffer', maxContentLength: -1 }); | |
| audioBuffer = Buffer.from(response.data); | |
| } else if (media instanceof Buffer) { | |
| audioBuffer = media; | |
| } else { | |
| throw new Error('Media harus berupa URL string atau Buffer.'); | |
| } | |
| const randomFilename = generateRandomName(10) + '.mp3'; | |
| const tmpFilePath = path.join(tempDir, randomFilename); | |
| fs.writeFileSync(tmpFilePath, audioBuffer); | |
| const tags = { title, artist, year }; | |
| if (typeof imagecover === 'string') { | |
| const response = await axios.get(imagecover, { responseType: 'arraybuffer' }); | |
| const coverBuffer = Buffer.from(response.data); | |
| tags.image = { | |
| mime: 'image/jpeg', | |
| type: { id: 3, name: 'Front Cover' }, | |
| description: 'Cover', | |
| imageBuffer: coverBuffer | |
| }; | |
| } else if (imagecover instanceof Buffer) { | |
| tags.image = { | |
| mime: 'image/jpeg', | |
| type: { id: 3, name: 'Front Cover' }, | |
| description: 'Cover', | |
| imageBuffer: imagecover | |
| }; | |
| } | |
| const success = nodeID3.write(tags, tmpFilePath); | |
| console[success ? 'log' : 'error'](success ? 'Tag ID3 berhasil diubah!' : 'Gagal mengubah tag ID3.'); | |
| return { msg: `Audio berhasil diubah.`, path: `${tmpFilePath}` }; | |
| } catch (error) { | |
| console.error('Terjadi kesalahan:', error); | |
| throw new Error('Terjadi kesalahan saat mengubah audio.'); | |
| } | |
| } | |
| // Fungsi untuk menghasilkan nama acak | |
| function generateRandomName(length) { | |
| const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; | |
| let randomName = ''; | |
| for (let i = 0; i < length; i++) { | |
| randomName += characters.charAt(Math.floor(Math.random() * characters.length)); | |
| } | |
| return randomName; | |
| } | |
| async function fetchCobaltOnly(url, opts = {}) { | |
| try { | |
| const response = await axios.post('https://cobalt.siputzx.my.id/', { url, ...opts }, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } } ); | |
| return response.data; | |
| } catch (error) { | |
| if (error.response) { | |
| const contentType = error.response.headers['content-type']; | |
| if (contentType && contentType.includes('json')) { | |
| throw error.response.data.message || 'An error occurred'; | |
| } | |
| throw error.response.statusText; | |
| } | |
| throw error.message; | |
| } | |
| } | |
| const servers = [ | |
| "https://cobalt.siputzx.my.id/", | |
| "https://c.blahaj.ca/", | |
| "https://api.co.waow.cat/", | |
| "https://cobalt-api.kwiatekmiki.com", | |
| "https://cobalt-backend.canine.tools/", | |
| "https://cobalt.api.timelessnesses.me/", | |
| "https://capi.3kh0.net" | |
| ]; | |
| async function cobalt(config) { | |
| try { | |
| if (!(typeof config === "object")) { | |
| throw new Error("Invalid config input, config must be a JSON object!"); | |
| } | |
| config = { | |
| url: config?.url || null, | |
| videoQuality: config?.videoQuality || "720", | |
| audioFormat: config?.audioFormat || "mp3", | |
| audioBitrate: config?.audioBitrate || "128", | |
| filenameStyle: config?.filenameStyle || "classic", | |
| downloadMode: config?.downloadMode || "auto", | |
| youtubeVideoCodec: config?.youtubeVideoCodec || "h264", | |
| youtubeDubLang: config?.youtubeDubLang || "en", | |
| alwaysProxy: config?.alwaysProxy || false, | |
| disableMetadata: config?.disableMetadata || false, | |
| tiktokFullAudio: config?.tiktokFullAudio || true, | |
| tiktokH265: config?.tiktokH265 || true, | |
| twitterGif: config?.twitterGif || true, | |
| youtubeHLS: config?.youtubeHLS || false, | |
| }; | |
| if (!config.url) { | |
| throw new Error("Missing URL input!"); | |
| } | |
| for (let i = 0; i < servers.length; i++) { | |
| try { | |
| console.log(`Trying server: ${servers[i]}`); // Log server yang dicoba | |
| const response = await axios.post(servers[i], config, { | |
| headers: { | |
| accept: "application/json", | |
| contentType: "application/json", | |
| }, | |
| }); | |
| const data = response.data; | |
| if (data.status === "error") { | |
| throw new Error("Failed to fetch content from server."); | |
| } | |
| console.log(`Success with server: ${servers[i]}`); // Log server sukses | |
| return { | |
| success: true, | |
| result: data, | |
| }; | |
| } catch (error) { | |
| if (i === servers.length - 1) { | |
| // Jika sudah mencoba semua server | |
| throw error; | |
| } | |
| console.warn(`Server ${servers[i]} failed. Trying next server...`); // Log server gagal | |
| } | |
| } | |
| } catch (error) { | |
| return { | |
| success: false, | |
| errors: error.message || error, | |
| }; | |
| } | |
| } | |
| async function fetchSaveTubeAPI(opts = {}) { | |
| const headers = { | |
| Authority: 'cdn59.savetube.su', | |
| 'Content-Type': 'application/json' | |
| }; | |
| try { | |
| const { data: info } = await axios.post(`https://${headers.Authority}/info`, opts, { headers }); | |
| opts.key = info.data.key; | |
| const { data: result } = await axios.post(`https://${headers.Authority}/download`, opts, { headers }); | |
| return result; | |
| } catch (error) { | |
| return { success: false, message: error.response?.data?.message || error.message }; | |
| } | |
| } | |
| async function getAudioMP3Url(videoUrl) { | |
| try { | |
| const id_video = await GetId(videoUrl); | |
| const infoVids = await getVideoDetailsWithApi(id_video); | |
| const obj = { | |
| type: 'audio', | |
| quality: 128, | |
| url: videoUrl | |
| }; | |
| const payload = { | |
| downloadType: obj.type !== 'video' ? 'audio' : 'video', | |
| quality: obj.quality ? String(obj.quality) : obj.type !== 'video' ? '128' : '720', | |
| url: obj.url | |
| }; | |
| const video = await fetchSaveTubeAPI(payload); | |
| const path_audio = path.join(tempDir, generateRandomName(10) + '.mp3'); | |
| const path_audio_edit = path_audio.replace('.mp3', '_edit.mp3'); | |
| // Download file audio | |
| const headers = { | |
| 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36', | |
| 'Referer': 'https://cobalt.tools/pustaka/' | |
| }; | |
| const response = await axios.get(video.data.downloadUrl, { responseType: 'arraybuffer', headers }); | |
| fs.writeFileSync(path_audio, response.data); | |
| // Periksa apakah file input valid | |
| if (!fs.existsSync(path_audio)) { | |
| throw new Error('File audio tidak ditemukan setelah diunduh.'); | |
| } | |
| if (fs.statSync(path_audio).size === 0) { | |
| throw new Error('File audio kosong atau rusak.'); | |
| } | |
| // Debugging tambahan: coba cek format file | |
| console.log(`File audio diunduh: ${path_audio}, size: ${fs.statSync(path_audio).size} bytes`); | |
| // Tambahkan metadata ke file yang diunduh | |
| await new Promise((resolve, reject) => { | |
| ffmpeg(path_audio) | |
| .outputOptions(['-acodec libmp3lame', '-ab 128k', '-ar 44100']) | |
| .on('start', (commandLine) => { | |
| console.log('FFmpeg command:', commandLine); // Log perintah FFmpeg | |
| }) | |
| .on('stderr', (stderrLine) => { | |
| console.error('FFmpeg stderr:', stderrLine); // Log error FFmpeg | |
| }) | |
| .on('end', async () => { | |
| try { | |
| // Tambahkan metadata | |
| const buffer = fs.readFileSync(path_audio_edit); // Ambil file hasil edit | |
| const edited = await addAudioTags(buffer, infoVids.title, infoVids.channelTitle, 2024, infoVids.thumbnail); | |
| // Ganti file lama dengan file yang sudah diedit | |
| const buffer2 = fs.readFileSync(edited.path); | |
| fs.writeFileSync(path_audio, buffer2); | |
| fs.unlinkSync(path_audio_edit); // Hapus file sementara | |
| resolve(); | |
| } catch (error) { | |
| reject(error); | |
| } | |
| }) | |
| .on('error', (err) => { | |
| console.error('FFmpeg conversion error:', err); | |
| reject(err); | |
| }) | |
| .save(path_audio_edit); // Simpan sementara dengan nama _edit.mp3 | |
| }); | |
| // Kembalikan hasil akhir | |
| return { | |
| status: 200, | |
| title: infoVids.title, | |
| result: { | |
| fileName: video.filename || infoVids.title + ".mp3", | |
| url_path: `https://${process.env.SPACE_HOST}/temp/${path.basename(path_audio)}`, | |
| curl_path: `https://${process.env.SPACE_HOST}/temp/${path.basename(path_audio)}?download=1&filename=${infoVids.title}`, | |
| path: path_audio | |
| }, | |
| infoVids | |
| }; | |
| } catch (error) { | |
| console.error('Error:', error); | |
| throw new Error('Failed to process audio URL'); | |
| } | |
| } | |
| app.get('/ytmp3', async (req, res) => { | |
| try { | |
| const { url } = req.query; | |
| if (!url) return res.status(400).json({ error: 'Parameter url is required' }); | |
| let result = await getAudioMP3Url(url); | |
| res.json(result); | |
| // Menghapus file setelah 10 menit | |
| try { | |
| await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes | |
| await fss.unlink(result.result.path); | |
| console.log(`File ${result.result.path} deleted.`); | |
| } catch (error) { | |
| console.error(`Error deleting file ${result.result.path}:`, error); | |
| } | |
| } catch (error) { | |
| console.error('Error processing request:', error); | |
| res.status(500).json({ | |
| error: 'Failed to process request\n' + error | |
| }); | |
| } | |
| }); | |
| async function fetchHtml(url) { | |
| // Launch browser dengan mode headless | |
| const browser = await puppeteer.launch({ | |
| headless: true, | |
| args: ['--no-sandbox', '--disable-setuid-sandbox', '--incognito', '--single-process', '--no-sandbox', '--no-zygote', '--no-cache'], | |
| timeout: 60000 // Timeout untuk peluncuran browser | |
| }); | |
| // Buat page baru | |
| const page = await browser.newPage(); | |
| // Set User Agent untuk menghindari deteksi bot | |
| //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'); | |
| 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;]"); | |
| // Navigasi ke URL yang diinginkan | |
| //await page.goto(url); | |
| await page.goto(url, { waitUntil: 'networkidle2' }); | |
| // Tunggu sampai page selesai loading | |
| //await page.waitForNavigation({ waitUntil: 'networkidle2' }); | |
| // Ambil HTML dari page | |
| const html = await page.content(); | |
| // Tutup browser | |
| await browser.close(); | |
| // Return HTML | |
| return html; | |
| } | |
| app.get('/html', async (req, res) => { | |
| try { | |
| const { url } = req.query; | |
| if (!url) return res.status(400).json({ error: 'Parameter url is required' }); | |
| let result = await fetchHtml(url); | |
| res.send(result); | |
| } catch (error) { | |
| console.error('Error processing request:', error); | |
| res.status(500).json({ | |
| error: 'Failed to process request\n' + error | |
| }); | |
| } | |
| }); | |
| async function XnDl(url) { | |
| const browser = await puppeteer.launch({ | |
| headless: true, | |
| args: ['--no-sandbox', '--disable-setuid-sandbox', '--incognito', '--single-process', '--no-sandbox', '--no-zygote', '--no-cache'], | |
| timeout: 60000 // Timeout untuk peluncuran browser | |
| }); | |
| try { | |
| const context = await browser.createBrowserContext(); | |
| // Create a new page inside context. | |
| const page = await context.newPage(); | |
| 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;]"); | |
| await page.goto(url.replace("xnxx.com", "xnxxvideodownload.com"), { | |
| waitUntil: 'domcontentloaded', | |
| timeout: 60000 // Timeout untuk navigasi | |
| }); | |
| await page.waitForNavigation({ | |
| waitUntil: 'networkidle0', | |
| timeout: 60000 // Timeout untuk menunggu navigasi selesai | |
| }); | |
| const data = await page.evaluate(() => { | |
| const title = document.querySelector("body > main > section.e.j.d2.dsection > h2")?.textContent || ''; | |
| const thumbnail = document.querySelector("body > main > section.e.j.d2.dsection > div > div.thumbdiv > img")?.src || ''; | |
| const url = document.querySelector("body > main > section.e.j.d2.dsection > div > div.thumbdiv > a")?.href || ''; | |
| const table = document.getElementById('dtable')?.getElementsByTagName('table')[0]; | |
| const videoDownload = []; | |
| if (table) { | |
| for (let i = 0; i < table.rows.length; i++) { | |
| const row = table.rows[i]; | |
| const rowData = { | |
| quality: row.cells[0]?.innerText || '', | |
| ext: row.cells[1]?.innerText || '', | |
| url: row.cells[2]?.getElementsByTagName('a')[0]?.href || '' | |
| }; | |
| videoDownload.push(rowData); | |
| } | |
| } | |
| return { title, thumbnail, url, videoDownload }; | |
| }); | |
| return data; | |
| } catch (error) { | |
| console.error('Error:', error); | |
| return null; | |
| } finally { | |
| await browser.close(); | |
| } | |
| } | |
| app.get('/xnxx', async (req, res) => { | |
| try { | |
| const { url } = req.query; | |
| if (!url) return res.status(400).json({ error: 'Parameter url is required' }); | |
| let result = await XnDl(url); | |
| res.send(result); | |
| } catch (error) { | |
| console.error('Error processing request:', error); | |
| res.status(500).json({ | |
| error: 'Failed to process request\n' + error | |
| }); | |
| } | |
| }); | |
| /* | |
| ┏┓┏━┓┏━━━┓┏━┓┏━┓┏━━┓┏┓┏━┓┏┓╋┏┓ | |
| ┃┃┃┏┛┃┏━┓┃┃┃┗┛┃┃┗┫┣┛┃┃┃┏┛┃┃╋┃┃ | |
| ┃┗┛┛╋┃┃╋┃┃┃┏┓┏┓┃╋┃┃╋┃┗┛┛╋┃┃╋┃┃ | |
| ┃┏┓┃╋┃┃╋┃┃┃┃┃┃┃┃╋┃┃╋┃┏┓┃╋┃┃╋┃┃ | |
| ┃┃┃┗┓┃┗━┛┃┃┃┃┃┃┃┏┫┣┓┃┃┃┗┓┃┗━┛┃ | |
| ┗┛┗━┛┗━━━┛┗┛┗┛┗┛┗━━┛┗┛┗━┛┗━━━┛ | |
| */ | |
| function generateRandomID(length = 8) { | |
| const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | |
| let result = ''; | |
| for (let i = 0; i < length; i++) { | |
| result += characters.charAt(Math.floor(Math.random() * characters.length)); | |
| } | |
| return result; | |
| } | |
| async function komiku_download(url) { | |
| const instanceID = generateRandomID(); | |
| const tempDir = path.join(tempDirBase, instanceID); | |
| await fss.mkdir(tempDir); | |
| // Extracting the title from the URL | |
| const title = url.split('/').filter(part => part).pop(); | |
| try { | |
| const response = await axios.get(url); | |
| const html = response.data; | |
| const $ = cheerio.load(html); | |
| const imgList = []; | |
| $('#Baca_Komik img').each((index, element) => { | |
| const src = $(element).attr('src'); | |
| imgList.push({ path: src }); | |
| }); | |
| await processImages(imgList, tempDir, instanceID); | |
| const pdfPath = await createPDF(instanceID, tempDir); | |
| console.log(`PDF berhasil dibuat: ${pdfPath}`); | |
| return { path: pdfPath, title: title, url: `https://${process.env.SPACE_HOST}/temp/${path.basename(pdfPathq)}` }; | |
| } catch (error) { | |
| console.log(error); | |
| throw error; | |
| } finally { | |
| await fss.rmdir(tempDir, { recursive: true }); | |
| } | |
| } | |
| async function downloadImage(image, tempDir, instanceID) { | |
| const response = await axios.get(image.path, { responseType: 'arraybuffer' }); | |
| const imagePath = path.join(tempDir, `image_${instanceID}_${Date.now()}_${Math.floor(Math.random() * 1000)}.jpg`); | |
| await writeFileAsync(imagePath, response.data); | |
| const imageHeight = await getImageHeight(imagePath); | |
| const newHeight = Math.floor(imageHeight * 0.7); | |
| const command = `convert ${imagePath} -resize 720x${newHeight}! -quality 75 -background white -gravity center -extent 720x${newHeight} ${imagePath}`; | |
| await execPromise(command); | |
| return imagePath; | |
| } | |
| async function getImageHeight(imagePath) { | |
| const { stdout } = await execPromise(`identify -format "%h" ${imagePath}`); | |
| return parseInt(stdout.trim()); | |
| } | |
| async function processImages(imgList, tempDir, instanceID) { | |
| const maxImagesPerPage = 10; // Maksimal 10 gambar per halaman | |
| let partIndex = 0; | |
| let partImages = []; | |
| for (let i = 0; i < imgList.length; i++) { | |
| const imagePath = await downloadImage(imgList[i], tempDir, instanceID); | |
| partImages.push(imagePath); | |
| if (partImages.length >= maxImagesPerPage) { | |
| await combineAndSave(partImages, partIndex, tempDir, instanceID); | |
| partImages = []; | |
| partIndex++; | |
| } | |
| } | |
| // Jika masih ada gambar yang belum diproses | |
| if (partImages.length > 0) { | |
| await combineAndSave(partImages, partIndex, tempDir, instanceID); | |
| } | |
| } | |
| async function combineAndSave(imagePaths, partIndex, tempDir, instanceID) { | |
| const combinedImagePath = path.join(tempDir, `combined_part_${instanceID}_${partIndex}.jpg`); | |
| const command = `convert ${imagePaths.join(' ')} -append -quality 75 ${combinedImagePath}`; | |
| await execPromise(command); | |
| imagePaths.forEach(fs.unlinkSync); | |
| return combinedImagePath; | |
| } | |
| async function createPDF(instanceID, tempDir) { | |
| const combinedParts = fs.readdirSync(tempDir).filter(file => file.startsWith(`combined_part_${instanceID}_`)); | |
| const combinedImagesPath = combinedParts.map(file => path.join(tempDir, file)).join(' '); | |
| const pdfPath = path.join(tempDir, `${instanceID}.pdf`); | |
| const createPDFCommand = `convert ${combinedImagesPath} ${pdfPath}`; | |
| await execPromise(createPDFCommand); | |
| return pdfPath; | |
| } | |
| app.get('/komiku/download', async (req, res) => { | |
| try { | |
| const { url } = req.query; | |
| if (!url) return res.status(400).json({ error: 'Parameter url is required' }); | |
| let result = await komiku_download(url); | |
| res.json(result); | |
| // Menghapus file setelah 10 menit | |
| try { | |
| await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes | |
| await fss.unlink(result.path); | |
| console.log(`File ${result.path} deleted.`); | |
| } catch (error) { | |
| console.error(`Error deleting file ${result.path}:`, error); | |
| } | |
| } catch (error) { | |
| console.error('Error processing request:', error); | |
| res.status(500).json({ | |
| error: 'Failed to process request\n' + error | |
| }); | |
| } | |
| }); | |
| /* | |
| V2 V2 V2 V2 | |
| */ | |
| async function komiku_downloadV2(url) { | |
| const instanceID = generateRandomID(); | |
| const tempDir = path.join(tempDirBase, instanceID); | |
| await fss.mkdir(tempDir); | |
| // Extracting the title from the URL | |
| const title = url.split('/').filter(part => part).pop(); | |
| let browser; | |
| try { | |
| browser = await puppeteer.launch({ | |
| headless: true, | |
| args: ['--no-sandbox', '--disable-setuid-sandbox'] | |
| }); | |
| const page = await browser.newPage(); | |
| await page.goto(url, { waitUntil: 'networkidle2' }); | |
| // Extracting images from the page | |
| const imgList = await page.evaluate(() => { | |
| return Array.from(document.querySelectorAll('#Baca_Komik img')).map(img => img.src); | |
| }); | |
| const images = imgList.map(src => ({ path: src })); | |
| await processImagesV2(images, tempDir, instanceID); | |
| const pdfPath = await createPDFV2(instanceID, tempDir); | |
| console.log(`PDF berhasil dibuat: ${pdfPath}`); | |
| return { path: pdfPath, title: title, url: `https://${process.env.SPACE_HOST}/temp/${path.basename(pdfPath)}` }; | |
| } catch (error) { | |
| console.log(error); | |
| throw error; | |
| } finally { | |
| if (browser) { | |
| await browser.close(); | |
| } | |
| await fss.rmdir(tempDir, { recursive: true }); | |
| } | |
| } | |
| async function downloadImageV2(image, tempDir, instanceID) { | |
| const response = await puppeteer.download(image.path, { responseType: 'arraybuffer' }); | |
| const imagePath = path.join(tempDir, `image_${instanceID}_${Date.now()}_${Math.floor(Math.random() * 1000)}.jpg`); | |
| await writeFileAsync(imagePath, response); | |
| const imageHeight = await getImageHeightV2(imagePath); | |
| const newHeight = Math.floor(imageHeight * 0.7); | |
| const command = `convert ${imagePath} -resize 720x${newHeight}! -quality 75 -background white -gravity center -extent 720x${newHeight} ${imagePath}`; | |
| await execPromise(command); | |
| return imagePath; | |
| } | |
| async function getImageHeightV2(imagePath) { | |
| const { stdout } = await execPromise(`identify -format "%h" ${imagePath}`); | |
| return parseInt(stdout.trim()); | |
| } | |
| async function processImagesV2(imgList, tempDir, instanceID) { | |
| const maxImagesPerPage = 10; // Maksimal 10 gambar per halaman | |
| let partIndex = 0; | |
| let partImages = []; | |
| for (let i = 0; i < imgList.length; i++) { | |
| const imagePath = await downloadImageV2(imgList[i], tempDir, instanceID); | |
| partImages.push(imagePath); | |
| if (partImages.length >= maxImagesPerPage) { | |
| await combineAndSaveV2(partImages, partIndex, tempDir, instanceID); | |
| partImages = []; | |
| partIndex++; | |
| } | |
| } | |
| // Jika masih ada gambar yang belum diproses | |
| if (partImages.length > 0) { | |
| await combineAndSaveV2(partImages, partIndex, tempDir, instanceID); | |
| } | |
| } | |
| async function combineAndSaveV2(imagePaths, partIndex, tempDir, instanceID) { | |
| const combinedImagePath = path.join(tempDir, `combined_part_${instanceID}_${partIndex}.jpg`); | |
| const command = `convert ${imagePaths.join(' ')} -append -quality 75 ${combinedImagePath}`; | |
| await execPromise(command); | |
| imagePaths.forEach(fs.unlinkSync); | |
| return combinedImagePath; | |
| } | |
| async function createPDFV2(instanceID, tempDir) { | |
| const combinedParts = fs.readdirSync(tempDir).filter(file => file.startsWith(`combined_part_${instanceID}_`)); | |
| const combinedImagesPath = combinedParts.map(file => path.join(tempDir, file)).join(' '); | |
| const pdfPath = path.join(tempDir, `${instanceID}.pdf`); | |
| const createPDFCommand = `convert ${combinedImagesPath} ${pdfPath}`; | |
| await execPromise(createPDFCommand); | |
| return pdfPath; | |
| } | |
| app.get('/komiku/downloadV2', async (req, res) => { | |
| try { | |
| const { url } = req.query; | |
| if (!url) return res.status(400).json({ error: 'Parameter url is required' }); | |
| let result = await komiku_downloadV2(url); | |
| res.json(result); | |
| // Menghapus file setelah 10 menit | |
| try { | |
| await new Promise(resolve => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes | |
| await fss.unlink(result.path); | |
| console.log(`File ${result.path} deleted.`); | |
| } catch (error) { | |
| console.error(`Error deleting file ${result.path}:`, error); | |
| } | |
| } catch (error) { | |
| console.error('Error processing request:', error); | |
| res.status(500).json({ | |
| error: 'Failed to process request\n' + error | |
| }); | |
| } | |
| }); | |
| /***********/ | |
| async function getLatestKomik(page) { | |
| const url = `https://api.komiku.id/manga/page/${page}/`; | |
| const headers = { | |
| 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36', | |
| 'Referer': 'https://komiku.id/pustaka/' | |
| }; | |
| try { | |
| const response = await axios.get(url, { headers }); | |
| const $ = cheerio.load(response.data); | |
| const mangaArray = []; | |
| // Scraping data | |
| $('.bge').each((index, element) => { | |
| const title = $(element).find('.kan h3').text().trim(); | |
| const link_komik = $(element).find('.bgei a').attr('href'); | |
| const imgSrc = $(element).find('.bgei img').attr('src'); | |
| const type = $(element).find('.tpe1_inf b').text().trim(); | |
| const type2 = $(element).find('.tpe1_inf').text().trim(); | |
| const description = $(element).find('.kan p').text().trim(); | |
| const readersInfo = $(element).find('.judul2').text().trim(); | |
| const latestChapter = "https://komiku.id" + $(element).find('.new1:last-child a').attr('href'); | |
| mangaArray.push({ | |
| title, | |
| link_komik, | |
| imgSrc, | |
| type, | |
| type2, | |
| description, | |
| readersInfo, | |
| latestChapter | |
| }); | |
| }); | |
| return mangaArray; | |
| } catch (error) { | |
| console.error('Error fetching the URL', error); | |
| throw error; | |
| } | |
| } | |
| async function GetKomik(url) { | |
| try { | |
| const response = await axios.get(url); | |
| const $ = cheerio.load(response.data); | |
| const cover = $('#Informasi > div > img').attr('src'); | |
| const judul = $('#Informasi > table > tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(); | |
| const jenis = $('#Informasi > table > tbody > tr:nth-child(3) > td:nth-child(2) > b').text().trim(); | |
| const konsepCerita = $('#Informasi > table > tbody > tr:nth-child(4) > td:nth-child(2)').text().trim(); | |
| const author = $('#Informasi > table > tbody > tr:nth-child(5) > td:nth-child(2)').text().trim(); | |
| const status = $('#Informasi > table > tbody > tr:nth-child(6) > td:nth-child(2)').text().trim(); | |
| const sinopsis = $('#Judul > p.desc').text().trim(); | |
| const genreElements = $('#Informasi > ul > li').map((i, el) => $(el).text().trim()).get(); | |
| const chapterElements = $('#daftarChapter > tr').map((i, el) => { | |
| if (i === 0) { | |
| return null; | |
| } | |
| return { | |
| judulSeries: $(el).find('td.judulseries > a').text().trim(), | |
| tanggalUpdate: $(el).find('td.tanggalseries').text().trim(), | |
| url: "https://komiku.id" + $(el).find('td.judulseries > a').attr('href') | |
| }; | |
| }).get().filter(chapter => chapter !== null); | |
| const mangaInfo = { | |
| cover, | |
| judul, | |
| sinopsis, | |
| jenis, | |
| konsepCerita, | |
| author, | |
| status, | |
| genres: genreElements, | |
| chapters: chapterElements | |
| }; | |
| return mangaInfo; | |
| } catch (error) { | |
| console.error('Error fetching the URL', error); | |
| throw error; | |
| } | |
| } | |
| app.get('/komiku/latest', async (req, res) => { | |
| try { | |
| const { page } = req.query; | |
| if (!page) return res.status(400).json({ error: 'Parameter page is required' }); | |
| let result = await getLatestKomik(page); | |
| res.json(result); | |
| } catch (error) { | |
| console.error('Error processing request:', error); | |
| res.status(500).json({ | |
| error: 'Failed to process request\n' + error | |
| }); | |
| } | |
| }); | |
| app.get('/komiku', async (req, res) => { | |
| try { | |
| const { url } = req.query; | |
| if (!url) return res.status(400).json({ error: 'Parameter url is required' }); | |
| let result = await GetKomik(url); | |
| res.json(result); | |
| } catch (error) { | |
| console.error('Error processing request:', error); | |
| res.status(500).json({ | |
| error: 'Failed to process request\n' + error | |
| }); | |
| } | |
| }); | |
| app.post("/cobalt", async (req, res) => { | |
| const config = req.body; | |
| try { | |
| if (!config.url) { | |
| return res.status(400).json({ | |
| success: false, | |
| message: "Missing 'url' in the request body.", | |
| }); | |
| } | |
| const result = await cobalt(config); | |
| if (result.success) { | |
| return res.status(200).json(result); | |
| } else { | |
| return res.status(500).json({ | |
| success: false, | |
| message: "Failed to process the request.", | |
| errors: result, | |
| }); | |
| } | |
| } catch (error) { | |
| res.status(500).json({ | |
| success: false, | |
| message: "Internal server error.", | |
| errors: error || error.message, | |
| }); | |
| } | |
| }); | |
| /******************* | |
| ┏┓┏━┓┏━━━┓┏━┓┏━┓┏━━┓┏┓┏━┓┏┓╋┏┓ | |
| ┃┃┃┏┛┃┏━┓┃┃┃┗┛┃┃┗┫┣┛┃┃┃┏┛┃┃╋┃┃ | |
| ┃┗┛┛╋┃┃╋┃┃┃┏┓┏┓┃╋┃┃╋┃┗┛┛╋┃┃╋┃┃ | |
| ┃┏┓┃╋┃┃╋┃┃┃┃┃┃┃┃╋┃┃╋┃┏┓┃╋┃┃╋┃┃ | |
| ┃┃┃┗┓┃┗━┛┃┃┃┃┃┃┃┏┫┣┓┃┃┃┗┓┃┗━┛┃ | |
| ┗┛┗━┛┗━━━┛┗┛┗┛┗┛┗━━┛┗┛┗━┛┗━━━┛ | |
| *********************/ | |
| async function iwaraDL(url) { | |
| const browser = await puppeteer.launch({ | |
| headless: true, | |
| args: ['--no-sandbox', '--disable-setuid-sandbox'] | |
| }); | |
| const page = await browser.newPage(); | |
| 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;]"); | |
| await page.goto("https://fetchfile.me/download-iwara/", { waitUntil: 'domcontentloaded' }); | |
| await page.type('#url', url); | |
| await page.click('#ring'); | |
| await page.waitForSelector('#result > div > div.youtube.col-md-7 > ul > li'); | |
| const title = await page.$eval('#result > div > div.youtube.col-md-7 > h2', el => el.innerText); | |
| const originalSource = await page.$eval('#mp4 > table > tbody > tr:nth-child(1) > td:nth-child(3) > a.dlw', el => el.href || null); | |
| const high = await page.$eval('#mp4 > table > tbody > tr:nth-child(2) > td:nth-child(3) > a.dlw', el => el.href || null); | |
| const standard = await page.$eval('#mp4 > table > tbody > tr:nth-child(3) > td:nth-child(3) > a.dlw', el => el.href || null); | |
| const low = await page.$eval('#mp4 > table > tbody > tr:nth-child(4) > td:nth-child(3) > a.dlw', el => el.href || null); | |
| let ht = await page.content(); | |
| console.log("\n========================\n\n\n " + ht + " \n========================\n") | |
| await browser.close(); | |
| return { | |
| title, | |
| originalSource: originalSource || 'Original source not available', | |
| high: high || 'High quality not available', | |
| standard: standard || 'Standard quality not available', | |
| low: low || 'Low quality not available' | |
| }; | |
| } | |
| // Rute untuk menerima data melalui query string (GET) | |
| app.get('/iwara/download', async (req, res) => { | |
| const { url } = req.query; | |
| if (!url) return res.status(400).json({ error: 'Parameter url is required' }); | |
| try { | |
| const base64Result = await iwaraDL(url); | |
| res.json(base64Result); // Mengirimkan buffer gambar sebagai respons | |
| } catch (error) { | |
| res.status(500).send(error); | |
| } | |
| }); | |
| async function XnxxDown(inputUrl) { | |
| const browser = await puppeteer.launch({ | |
| headless: true, | |
| args: ['--no-sandbox', '--disable-setuid-sandbox', '--incognito', '--single-process', '--no-sandbox', '--no-zygote', '--no-cache'] | |
| }); | |
| const page = await browser.newPage(); | |
| 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;]"); | |
| await page.goto(`https://www.locoloader.com/?url=${encodeURIComponent(inputUrl)}`, { waitUntil: 'domcontentloaded' }); | |
| await page.waitForSelector("#extraction > div > div.hl > h1 > a"); | |
| const title = await page.$eval( | |
| "#extraction > div > div.hl > h1 > a", | |
| el => el.innerText.trim() | |
| ); | |
| const url = await page.$eval( | |
| "#extraction > div > div.hl > h1 > a", | |
| el => el.href | |
| ); | |
| const img = await page.$eval( | |
| "#extraction > div > div.content-final-single__thumb-wrapper > div > div > img", | |
| el => el.src | |
| ); | |
| const type = await page.$eval( | |
| "#extraction > div > div:nth-child(3) > div.display-table-cell.linkInfo > div.icon-media", | |
| el => el.innerText.trim() | |
| ); | |
| const downloadLink = await page.$eval( | |
| "#extraction > div > div:nth-child(3) > div.display-table-cell.linkButtons > a.bt.dl", | |
| el => el.href | |
| ); | |
| await browser.close(); | |
| return { title, url, img, type, downloadLink }; | |
| } | |
| app.get('/xnxx/download', async (req, res) => { | |
| const { url } = req.query; | |
| if (!url) return res.status(400).json({ error: 'Parameter url is required' }); | |
| try { | |
| const base64Result = await XnxxDown(url); | |
| res.json(base64Result); // Mengirimkan buffer gambar sebagai respons | |
| } catch (error) { | |
| res.status(500).send(error); | |
| } | |
| }); | |
| /*******************************/ | |
| // Fungsi untuk ping website | |
| async function pingWebsite() { | |
| const browser = await puppeteer.launch({ | |
| headless: true, | |
| args: ['--no-sandbox', '--disable-setuid-sandbox'] | |
| }); | |
| const page = await browser.newPage(); | |
| 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;]"); | |
| await page.goto('https://huggingface.co/spaces/ArashiCode/api'); | |
| console.log("Ping"); | |
| await browser.close(); | |
| } | |
| // Ping website setiap 5 jam | |
| async function pingEvery5Hours() { | |
| await pingWebsite(); | |
| setInterval(async () => { | |
| await pingWebsite(); | |
| }, 5 * 60 * 60 * 1000); // 5 hours in milliseconds | |
| } | |
| // Mulai ping | |
| pingEvery5Hours(); | |
| app.listen(PORT, () => { | |
| console.log(`Server is running on port ${PORT}`); | |
| }); |