| 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}`); |
| }); |