nsfw / index.js
Closure-RI's picture
Update index.js
fb5c1a9 verified
raw
history blame
40.4 kB
import axios from 'axios';
import * as cheerio from 'cheerio';
import { createRequire } from 'module';
import os from 'os';
import express from 'express';
import { promisify } 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');
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 _return;
try {
_return = /await/i.test(code)
? await eval(`(async () => { ${code} })()`)
: eval(code);
} catch (err) {
_return = err.toString();
}
// 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(jsonFormatted);
} catch (err) {
return res.json({ error: "Invalid JSON format", result: _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://c.blahaj.ca/', { 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://co.eepy.today/",
"https://cdn1.meow.gs/",
"https://cdn2.meow.gs/",
"https://cdn3.meow.gs/",
"https://cdn4.meow.gs/",
"https://cdn5.meow.gs/",
];
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 getAudioMP3Url(videoUrl) {
try {
const id_video = await GetId(videoUrl);
const infoVids = await getVideoDetailsWithApi(id_video);
const video = await fetchCobaltOnly(videoUrl, { downloadMode: "audio", audioBitrate: "128", filenameStyle: "pretty", audioFormat: "mp3"})
console.log(video)
// Unduh file audio terlebih dahulu
/*
const video = await cobalt({
url: videoUrl,
downloadMode: "audio",
filenameStyle: "pretty",
audioFormat: "mp3",
audioBitrate: "128"
})
*/
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.url, { 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,
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();
// 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'],
timeout: 60000 // Timeout untuk peluncuran browser
});
try {
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(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']
});
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}`);
});