|
import { createRequire } from 'module'; |
|
import { fileURLToPath } from 'url'; |
|
import path from 'path'; |
|
import PDFDocument from 'pdfkit'; |
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
|
const require = createRequire(import.meta.url); |
|
|
|
const { promisify } = require('util'); |
|
const express = require('express'); |
|
const axios = require('axios'); |
|
const cheerio = require('cheerio'); |
|
const fs = require('fs'); |
|
const { tmpdir } = require('os'); |
|
const { join } = require('path'); |
|
const nodeID3 = require('node-id3'); |
|
const puppeteer = require('puppeteer'); |
|
const app = express(); |
|
const PORT = 7860; |
|
const { format } = require("util"); |
|
const os = require("os"); |
|
const writeFileAsync = promisify(fs.writeFile); |
|
const fss = fs.promises; |
|
|
|
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(os.tmpdir(), instanceID); |
|
await fss.mkdir(tempDir); |
|
|
|
|
|
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 }); |
|
}); |
|
|
|
const imagePaths = await downloadImages(imgList, tempDir, instanceID); |
|
const pdfPath = await createPDF(imagePaths, instanceID, tempDir); |
|
|
|
console.log(`PDF berhasil dibuat: ${pdfPath}`); |
|
return { path: pdfPath, title: title }; |
|
} 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); |
|
|
|
return imagePath; |
|
} |
|
|
|
async function downloadImages(imgList, tempDir, instanceID) { |
|
const imagePaths = []; |
|
for (const img of imgList) { |
|
const imagePath = await downloadImage(img, tempDir, instanceID); |
|
imagePaths.push(imagePath); |
|
} |
|
return imagePaths; |
|
} |
|
|
|
async function createPDF(imagePaths, instanceID, tempDir) { |
|
const pdfPath = path.join(os.tmpdir(), `${instanceID}.pdf`); |
|
const doc = new PDFDocument({ autoFirstPage: false }); |
|
|
|
doc.pipe(fs.createWriteStream(pdfPath)); |
|
|
|
for (const imagePath of imagePaths) { |
|
const { width, height } = await getImageDimensions(imagePath); |
|
doc.addPage({ size: [width, height] }); |
|
doc.image(imagePath, 0, 0, { width: width, height: height }); |
|
} |
|
|
|
doc.end(); |
|
|
|
return pdfPath; |
|
} |
|
|
|
async function getImageDimensions(imagePath) { |
|
const { promisify } = require('util'); |
|
const sizeOf = promisify(require('image-size')); |
|
const dimensions = await sizeOf(imagePath); |
|
return dimensions; |
|
} |
|
|
|
app.get('/komikudl', async (req, res) => { |
|
const url = req.query.url; |
|
|
|
if (!url) { |
|
return res.status(400).send('URL is required'); |
|
} |
|
|
|
try { |
|
const data = await komiku_download(url); |
|
res.download(data.path, `${data.title}.pdf`, (err) => { |
|
if (err) { |
|
console.error(err); |
|
} |
|
|
|
fs.unlinkSync(data.path); |
|
}); |
|
} catch (error) { |
|
res.status(500).send('An error occurred while generating the PDF'); |
|
} |
|
}); |
|
|
|
app.get('/add', async (req, res) => { |
|
try { |
|
const { url, title, artist, year, imgUrl } = req.query; |
|
|
|
const response = await axios.get(url, { |
|
responseType: 'arraybuffer' |
|
}); |
|
|
|
const audioBuffer = Buffer.from(response.data); |
|
|
|
const randomFilename = Math.random().toString(36).substring(7) + '.mp3'; |
|
|
|
const tmpFilePath = join(tmpdir(), randomFilename); |
|
|
|
fs.writeFileSync(tmpFilePath, audioBuffer); |
|
|
|
const tags = { |
|
title: title, |
|
artist: artist, |
|
year: year |
|
|
|
}; |
|
|
|
if (imgUrl) { |
|
const coverResponse = await axios.get(imgUrl, { |
|
responseType: 'arraybuffer' |
|
}); |
|
const coverBuffer = Buffer.from(coverResponse.data); |
|
tags.image = { |
|
mime: 'image/jpeg', |
|
type: { |
|
id: 3, |
|
name: 'Front Cover' |
|
}, |
|
description: 'Cover', |
|
imageBuffer: coverBuffer |
|
}; |
|
} |
|
|
|
|
|
const success = nodeID3.write(tags, tmpFilePath); |
|
|
|
if (success) { |
|
console.log('Tag ID3 berhasil diubah!'); |
|
} else { |
|
console.error('Gagal mengubah tag ID3.'); |
|
} |
|
|
|
|
|
const downloadLink = `https://${process.env.SPACE_HOST}/download/${randomFilename}`; |
|
res.json({ msg: `Audio berhasil diubah.`, link: downloadLink }); |
|
} catch (error) { |
|
console.error('Terjadi kesalahan:', error); |
|
res.status(500).send('Terjadi kesalahan saat mengubah audio.'); |
|
} |
|
}); |
|
|
|
async function delay(ms) { |
|
return new Promise(resolve => setTimeout(resolve, ms)); |
|
} |
|
|
|
|
|
app.get('/download/:filename', async (req, res) => { |
|
const { filename } = req.params; |
|
const filePath = join(tmpdir(), filename); |
|
res.download(filePath, () => { |
|
|
|
fs.unlinkSync(filePath); |
|
}); |
|
}); |
|
|
|
const startTime = new Date(); |
|
|
|
|
|
function waktuBerjalan() { |
|
const sekarang = new Date(); |
|
const selisih = sekarang.getTime() - startTime.getTime(); |
|
|
|
const hari = Math.floor(selisih / (1000 * 60 * 60 * 24)); |
|
const jam = Math.floor((selisih % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); |
|
const menit = Math.floor((selisih % (1000 * 60 * 60)) / (1000 * 60)); |
|
const detik = Math.floor((selisih % (1000 * 60)) / 1000); |
|
|
|
if (hari > 0) { |
|
return `${hari} hari ${jam} jam ${menit} menit ${detik} detik`; |
|
} else if (jam > 0) { |
|
return `${jam} jam ${menit} menit ${detik} detik`; |
|
} else if (menit > 0) { |
|
return `${menit} menit ${detik} detik`; |
|
} else { |
|
return `${detik} detik`; |
|
} |
|
} |
|
|
|
|
|
app.get('/ping', (req, res) => { |
|
res.send('Server is up and running!' + waktuBerjalan()); |
|
}); |
|
|
|
const pingServer = async () => { |
|
try { |
|
const pingResponse = await axios.get(`https://${process.env.SPACE_HOST}` + '/ping'); |
|
console.log('Server pinged at:', new Date().toLocaleTimeString()); |
|
} catch (error) { |
|
console.error('Failed to ping server:', error.message); |
|
} |
|
}; |
|
|
|
|
|
|
|
async function searchResepPuppeter(query, hal) { |
|
let pages = "https://cookpad.com/id/cari/" + query + "?event=search.typed_query" |
|
if(hal > 1) { |
|
pages += "&page=" + hal; |
|
} |
|
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.setExtraHTTPHeaders({ |
|
'Referer': pages |
|
}); |
|
await page.goto(pages); |
|
|
|
const baseUrl = page.url(); |
|
|
|
let jason = { |
|
list: [], |
|
next_page: false |
|
}; |
|
const liHtmlArray = jason.list; |
|
|
|
const ulElement = await page.$("#main_contents > div.lg\\:flex.lg\\:items-start > div.relative.lg\\:w-3\\/5 > ul"); |
|
if (ulElement) { |
|
const listItemsWithId = await ulElement.$$("li[id]"); |
|
|
|
for (const li of listItemsWithId) { |
|
const linkElement = await li.$("div.flex-auto.m-sm > div > div.flex.justify-between > h2 > a"); |
|
const imageElement = await li.$("div.flex-none.w-20.xs\\:w-auto.h-auto > picture > img"); |
|
const authorElement = await li.$("div.flex-auto.m-sm > div > div.border-t.border-dashed.border-cookpad-gray-400.pt-sm.mt-auto > div > span.break-all.clamp-1 > span"); |
|
|
|
const li_url = await (await linkElement.getProperty('href')).jsonValue(); |
|
const li_text = await (await linkElement.getProperty('innerText')).jsonValue(); |
|
const li_img = await (await imageElement.getProperty('src')).jsonValue(); |
|
const li_author = await (await authorElement.getProperty('innerText')).jsonValue(); |
|
|
|
let anu = { |
|
url: li_url, |
|
title: li_text, |
|
thumbnail: li_img, |
|
author: li_author |
|
}; |
|
liHtmlArray.push(anu); |
|
} |
|
} else { |
|
console.error("Element <ul> tidak ditemukan."); |
|
} |
|
|
|
jason.title = await page.$eval("#search-recipes-header > div > h1", element => element.innerText); |
|
|
|
const nextPageElement = await page.$("#main_contents > div.lg\\:flex.lg\\:items-start > div.relative.lg\\:w-3\\/5 > div.pagination.my-lg > a:nth-child(9)"); |
|
if (nextPageElement) { |
|
const nextPageHref = await (await nextPageElement.getProperty('href')).jsonValue(); |
|
jason.next_page = nextPageHref; |
|
} else { |
|
const nextPageElementAlt = await page.$("#main_contents > div.lg\\:flex.lg\\:items-start > div.relative.lg\\:w-3\\/5 > div.pagination.my-lg > a"); |
|
if (nextPageElementAlt) { |
|
const nextPageHrefAlt = await (await nextPageElementAlt.getProperty('href')).jsonValue(); |
|
jason.next_page = nextPageHrefAlt; |
|
} else { |
|
jason.next_page = false; |
|
} |
|
} |
|
|
|
await browser.close(); |
|
|
|
return jason; |
|
} |
|
|
|
async function getRecipeData(url) { |
|
try { |
|
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(url); |
|
|
|
|
|
await page.waitForSelector("#recipe_image > a > div > picture > img"); |
|
|
|
const title = await page.evaluate(() => document.querySelector("#recipe > div > div.md\\:w-2\\/3.flex-shrink-0 > div > h1").innerText.trim()); |
|
const author = await page.evaluate(() => document.querySelector("#recipe > div > div.md\\:w-2\\/3.flex-shrink-0 > div > a > div > div.clamp-1 > span.text-cookpad-14.text-cookpad-gray-700.font-semibold").innerText); |
|
const authorId = await page.evaluate(() => document.querySelector("#recipe > div > div.md\\:w-2\\/3.flex-shrink-0 > div > a > div > div.clamp-1 > span.text-cookpad-12.text-cookpad-gray-600").innerText); |
|
const authorProfileLink = await page.evaluate(() => document.querySelector("#recipe > div > div.md\\:w-2\\/3.flex-shrink-0 > div > a").href); |
|
const messageFromAuthor = await page.evaluate(() => document.querySelector("#recipe > div > div.md\\:w-2\\/3.flex-shrink-0 > meta:nth-child(3)").content || ""); |
|
const linkPage = await page.evaluate(() => document.querySelector("#recipe > div > div.md\\:w-2\\/3.flex-shrink-0 > link").href); |
|
|
|
|
|
const thumbnail = await page.$eval("#recipe_image > a > div > picture > img", img => img.src) |
|
.catch(() => "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQIchzBjMg4dcOYFswOtv5c1NUOutP5fRGviA&usqp=CAU"); |
|
|
|
const ingredientsList = await page.$$eval("#ingredients > div.ingredient-list > ol > li[id]", lis => lis.map(li => li.innerText)); |
|
|
|
const stepsList = await page.$$eval("#steps > ol > li[id]", lis => { |
|
return lis.map(li => { |
|
const stepText = li.querySelector("div:nth-child(2) > p").innerText; |
|
let stepImage = null; |
|
const imageAnchor = li.querySelector("div.-mx-rg.px-rg.flex.space-x-sm.mb-sm.overflow-auto.scroll-bar-hidden > a:nth-child(1)"); |
|
if (imageAnchor) { |
|
stepImage = imageAnchor.querySelector("picture > img").src; |
|
} |
|
return { |
|
text: stepText, |
|
image: stepImage |
|
}; |
|
}); |
|
}); |
|
|
|
await browser.close(); |
|
|
|
const recipeData = { |
|
title: title, |
|
author: author, |
|
authorId: authorId, |
|
authorProfileLink: authorProfileLink, |
|
messageFromAuthor: messageFromAuthor, |
|
linkPage: linkPage, |
|
thumb: thumbnail, |
|
ingredients: ingredientsList, |
|
steps: stepsList |
|
}; |
|
|
|
return recipeData; |
|
} catch (error) { |
|
console.error("Error:", error); |
|
return null; |
|
} |
|
} |
|
|
|
|
|
app.get('/cookpad', async (req, res) => { |
|
try { |
|
const query = req.query.query; |
|
const page = req.query.page || 1; |
|
const resep_search = await searchResepPuppeter(query, page); |
|
res.json(resep_search); |
|
} catch (e) { |
|
console.error(e); |
|
res.status(500).json({ error: 'Internal Server Error \n' + e}); |
|
} |
|
}); |
|
|
|
app.get('/get-cookpad', async (req, res) => { |
|
try { |
|
const url = req.query.url; |
|
const recipeData = await getRecipeData(url); |
|
res.json(recipeData); |
|
} catch (e) { |
|
console.error(e); |
|
res.status(500).json({ error: 'Internal Server Error \n' + e }); |
|
} |
|
}); |
|
|
|
app.get('/eval', async (req, res) => { |
|
try { |
|
const text_input = req.query.cmd; |
|
|
|
let evalCmd = ""; |
|
try { |
|
evalCmd = /await/i.test(text_input) ? await eval("(async() => { " + text_input + " })()") : eval(text_input); |
|
} catch (e) { |
|
evalCmd = e; |
|
} |
|
|
|
new Promise(async (resolve, reject) => { |
|
try { |
|
resolve(evalCmd); |
|
} catch (err) { |
|
reject(err); |
|
} |
|
}) |
|
.then((result) => { |
|
res.send(format(result)); |
|
}) |
|
.catch((err) => { |
|
res.send(format(err)); |
|
}); |
|
} catch (e) { |
|
console.error(e); |
|
res.status(500).json({ error: 'Internal Server Error \n' + e }); |
|
} |
|
}); |
|
|
|
async function waitForElementOrClose(page, selector, maxTries = 15) { |
|
for (let i = 0; i < maxTries; i++) { |
|
try { |
|
await page.waitForSelector(selector); |
|
console.log(`Element '${selector}' found.`); |
|
return true; |
|
} catch (error) { |
|
console.log(`Element '${selector}' not found. Retrying...`); |
|
if (i === maxTries - 1) { |
|
console.log(`Max retries reached. Closing the browser.`); |
|
return false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
app.get('/r34', async (req, res) => { |
|
try { |
|
const url = req.query.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.setExtraHTTPHeaders({ |
|
'Referer': 'https://www.pornloaders.com/rule34video-download/' |
|
}); |
|
|
|
|
|
await page.goto('https://www.pornloaders.com/rule34video-download/'); |
|
|
|
await page.type('#__next > main > div > div.DownloadPage_Hero__hoO8_ > form > div > input', url); |
|
|
|
|
|
await page.click('#__next > main > div > div.DownloadPage_Hero__hoO8_ > form > div > button'); |
|
|
|
const elementFound = await waitForElementOrClose(page, '#__next > main > div > div.DownloadPage_Hero__hoO8_ > div.DownloadPage_Loading__Yp4ut > div > a'); |
|
if (elementFound) { |
|
|
|
const href = await page.evaluate(() => { |
|
const element = document.querySelector('#__next > main > div > div.DownloadPage_Hero__hoO8_ > div.DownloadPage_Loading__Yp4ut > div > a'); |
|
return element ? element.href : null; |
|
}); |
|
|
|
if (href) { |
|
res.json({url: href}); |
|
} else { |
|
res.status(404).json({ error: 'Element not found or href attribute is missing.' }); |
|
} |
|
|
|
await browser.close(); |
|
} |
|
|
|
} catch (e) { |
|
console.error(e); |
|
res.status(500).json({ |
|
error: 'Internal Server Error \n' + e |
|
}); |
|
} |
|
}); |
|
|
|
app.get('/r34/v2', async (req, res) => { |
|
try { |
|
const url = req.query.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.setExtraHTTPHeaders({ |
|
'Referer': 'https://pastedownload.com/rule34video-video-downloader/' |
|
}); |
|
|
|
|
|
await page.goto('https://pastedownload.com/rule34video-video-downloader/'); |
|
|
|
await page.type('#url', url); |
|
|
|
|
|
await page.click('#send > div'); |
|
|
|
const elementFound = await waitForElementOrClose(page, '#links > div.col-md-4 > div.video-details > img'); |
|
if (elementFound) { |
|
|
|
const href = await page.evaluate(() => { |
|
const url1 = document.querySelector("#links > div.col-md-8.video-links > div:nth-child(2) > a").href; |
|
const url2 = document.querySelector("#links > div.col-md-8.video-links > div:nth-child(3) > a").href; |
|
const url3 = document.querySelector("#links > div.col-md-8.video-links > div:nth-child(4) > a").href; |
|
return [url1,url2,url3]; |
|
}); |
|
|
|
|
|
if (href) { |
|
res.json(href); |
|
} else { |
|
res.status(404).json({ error: 'Element not found or href attribute is missing.' }); |
|
} |
|
|
|
await browser.close(); |
|
} |
|
|
|
} catch (e) { |
|
console.error(e); |
|
res.status(500).json({ |
|
error: 'Internal Server Error \n' + e |
|
}); |
|
} |
|
}); |
|
|
|
|
|
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/Nexchan/yutub'); |
|
console.log("Ping"); |
|
await browser.close(); |
|
} |
|
|
|
|
|
async function pingEvery5Hours() { |
|
await pingWebsite(); |
|
setInterval(async () => { |
|
await pingWebsite(); |
|
}, 5 * 60 * 60 * 1000); |
|
} |
|
|
|
|
|
pingEvery5Hours(); |
|
|
|
|
|
app.listen(PORT, () => { |
|
console.log(`Server berjalan di port ${PORT}`); |
|
}); |