const fs = require('fs') const os = require('os') const util = require('util') const axios = require('axios') const bytes = require('bytes') const sharp = require('sharp') const morgan = require('morgan') const express = require('express') const cp = require('child_process') const PDFDocument = require('pdfkit') const playwright = require('playwright-extra') const cookieParser = require('cookie-parser'); const { Buffer } = require('buffer'); const querystring = require('querystring'); // const stealth = require('puppeteer-extra-plugin-stealth') // playwright.chromium.use(stealth()) const { NinexbuddySource, NinexbuddyScraper } = require("./lib/buddy.js") const kyou = new NinexbuddyScraper() const userSessions = {}; const app = express() app.set('json spaces', 4) app.use(morgan('dev')) app.use(cookieParser()); const CLIENT_ID = process.env.CLIENT_ID || 'your_client_id'; const CLIENT_SECRET = process.env.CLIENT_SECRET || 'your_client_secret'; const limitSize = '500mb' app.use(express.json({ limit: limitSize })) app.use(express.urlencoded({ extended: true, limit: limitSize })) const tmpFolder = os.tmpdir() app.use((req, res, next) => { fs.readdirSync(tmpFolder).map(file => { file = `${tmpFolder}/${file}` let stats = fs.statSync(file) if (!stats.isFile()) return if (Date.now() - stats.mtimeMs >= 1000 * 60 * 30) { fs.unlinkSync(file) console.log('Deleted file', file) } }) next() }) function getFrontendUri(req) { return `https://${req.get('host')}`; } async function getUserData(accessToken) { const response = await axios.get('https://api.spotify.com/v1/me', { headers: { 'Authorization': `Bearer ${accessToken}` } }); return response.data; } app.use('/file', express.static(tmpFolder)) app.all('/', (req, res) => { const status = {} const used = process.memoryUsage() for (let key in used) status[key] = formatSize(used[key]) const disk = cp.execSync('du -sh').toString().split('M')[0] status.diskUsage = `${disk} MB` const totalmem = os.totalmem() const freemem = os.freemem() status.memoryUsage = `${formatSize(totalmem - freemem)} / ${formatSize(totalmem)}` res.json({ creator: '@rippanteq7', message: 'Hello World', uptime: new Date(process.uptime() * 1000).toUTCString().split(' ')[4], status }) }) app.get('/proxy', async (req, res) => { const { url } = req.query; if (!url) return res.json({ success: false, message: 'Required parameter url' }); try { const response = await axios({ method: 'get', url, responseType: 'stream', headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', 'Referer': url } }); // Mengatur header agar tetap sesuai dengan respons asli res.set(response.headers); // Streaming langsung ke response response.data.pipe(res); } catch (error) { console.error(error.message); res.status(500).json({ success: false, message: 'Error fetching video' }); } }); async function refreshAccessToken(refreshToken) { const response = await axios.post('https://accounts.spotify.com/api/token', querystring.stringify({ grant_type: 'refresh_token', refresh_token: refreshToken, }), { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64'), }, }); return response.data; } // 1. Current Playback Endpoint with User ID app.get('/api/current-playback', async (req, res) => { try { const userId = req.query.user; if (!userId || !userSessions[userId]) { return res.status(401).json({ error: 'Not authenticated', solution: 'Please login at /login first' }); } const session = userSessions[userId]; // Refresh token if needed if (Date.now() >= session.expiresAt) { try { const newTokens = await refreshAccessToken(session.refreshToken); session.accessToken = newTokens.access_token; session.expiresAt = Date.now() + newTokens.expires_in * 1000; } catch (error) { delete userSessions[userId]; return res.status(401).json({ error: 'Session expired' }); } } // Prepare request parameters const params = {}; if (session.country) { params.market = session.country; } // Get current playback state const response = await axios.get('https://api.spotify.com/v1/me/player', { params, headers: { 'Authorization': `Bearer ${session.accessToken}`, 'Content-Type': 'application/json' }, }); // Handle no content response if (response.status === 204) { return res.json({ status: 'success', data: null, message: 'No active playback detected' }); } // Format playback data const playbackData = { device: { id: response.data.device.id, name: response.data.device.name, type: response.data.device.type, is_active: response.data.device.is_active, volume_percent: response.data.device.volume_percent }, track: { id: response.data.item.id, name: response.data.item.name, duration_ms: response.data.item.duration_ms, progress_ms: response.data.progress_ms, is_playing: response.data.is_playing, artists: response.data.item.artists.map(artist => ({ id: artist.id, name: artist.name })), album: { id: response.data.item.album.id, name: response.data.item.album.name, images: response.data.item.album.images, release_date: response.data.item.album.release_date } }, context: response.data.context ? { type: response.data.context.type, href: response.data.context.href, uri: response.data.context.uri } : null, shuffle_state: response.data.shuffle_state, repeat_state: response.data.repeat_state, timestamp: response.data.timestamp }; res.json({ status: 'success', user: { id: userId, display_name: session.display_name, country: session.country }, data: playbackData }); } catch (error) { console.error('Playback error:', error.response?.data || error.message); if (error.response?.status === 401) { return res.status(401).json({ error: 'Invalid or expired token' }); } res.status(500).json({ error: 'Failed to get playback state', details: error.response?.data || error.message }); } }); // 2. Login Endpoint app.get('/spotify', (req, res) => { const FRONTEND_URI = getFrontendUri(req); const REDIRECT_URI = `${FRONTEND_URI}/callback`; const scopes = [ 'user-read-playback-state', 'user-read-currently-playing', 'user-read-private', 'user-read-email' ]; const queryParams = querystring.stringify({ response_type: 'code', client_id: CLIENT_ID, scope: scopes.join(' '), redirect_uri: REDIRECT_URI, show_dialog: true, }); res.redirect(`https://accounts.spotify.com/authorize?${queryParams}`); }); // 3. Callback Endpoint app.get('/callback', async (req, res) => { const FRONTEND_URI = getFrontendUri(req); const REDIRECT_URI = `${FRONTEND_URI}/callback`; const { code, error } = req.query; if (error) { return res.redirect(`${FRONTEND_URI}/error?message=${encodeURIComponent(error)}`); } try { // Get tokens const authResponse = await axios.post('https://accounts.spotify.com/api/token', querystring.stringify({ grant_type: 'authorization_code', code, redirect_uri: REDIRECT_URI, }), { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ' + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64'), }, }); const { access_token, refresh_token, expires_in } = authResponse.data; // Get user data const userResponse = await axios.get('https://api.spotify.com/v1/me', { headers: { 'Authorization': `Bearer ${access_token}` }, }); // Store user session const userId = userResponse.data.id; userSessions[userId] = { accessToken: access_token, refreshToken: refresh_token, expiresAt: Date.now() + expires_in * 1000, display_name: userResponse.data.display_name, country: userResponse.data.country, email: userResponse.data.email }; // Redirect to current playback with user ID res.redirect(`${FRONTEND_URI}/api/current-playback?user=${userId}`); } catch (err) { console.error('Callback error:', err); res.redirect(`${FRONTEND_URI}/error?message=${encodeURIComponent('Authentication failed')}`); } }); app.get('/pages', async (req, res) => { const targetUrl = req.query.url; if (!targetUrl) { return res.status(400).json({ error: 'Parameter "url" dibutuhkan' }); } const browser = await playwright.chromium.launch({ headless: true, executablePath: '/usr/bin/chromium', // pastikan path ini benar di server kamu args: ['--no-sandbox'] }); const context = await browser.newContext({ extraHTTPHeaders: { 'accept': '*/*', 'accept-language': 'en-US,en;q=0.9,id;q=0.8', 'cache-control': 'no-cache', 'origin': 'https://doujindesu.tv', 'pragma': 'no-cache', 'referer': 'https://doujindesu.tv', 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'script', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'cross-site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' } }); try { const page = await context.newPage(); await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 60000 }); // Tunggu ekstra jika perlu ngelewatin challenge await page.waitForTimeout(8000); const content = await page.content(); res.send(content); } catch (err) { res.status(500).json({ error: 'Gagal fetch halaman', detail: err.message }); } finally { await browser.close(); } }); app.all('/imagetopdf', async (req, res) => { if (!['POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' }) try { console.log(new Date().toLocaleString('id', { timeZone: 'Asia/Jakarta' }), '\n', req.body) const { images } = req.body if (!(images && Array.isArray(images))) return res.json({ success: false, message: 'Required an array image url' }) const buffer = await toPDF(images) res.setHeader('Content-Disposition', `attachment; filename=${Math.random().toString(36).slice(2)}.pdf`) res.setHeader('Content-Type', 'application/pdf') res.setHeader('Content-Length', buffer.byteLength) res.send(buffer) } catch (e) { console.log(e) e = String(e) res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e }) } }) app.all('/webp2png', async (req, res) => { if (!['POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' }) try { const { file } = req.body if (!(file && isBase64(file))) return res.json({ success: false, message: 'Payload body file must be filled in base64 format' }) const fileBuffer = Buffer.from(file, 'base64') const fileName = `${Math.random().toString(36).slice(2)}.png` const convertData = await sharp(fileBuffer).png().toBuffer() await fs.promises.writeFile(`${tmpFolder}/${fileName}`, convertData) res.send(`https://${req.get('host')}/file/${fileName}`) } catch (e) { console.log(e) e = String(e) res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e }) } }) app.all(['/webp2gif', '/webp2mp4'], async (req, res) => { if (!['POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' }) try { const { file } = req.body if (!(file && isBase64(file))) return res.json({ success: false, message: 'Payload body file must be filled in base64 format' }) const fileBuffer = Buffer.from(file, 'base64') const fileName = `${Math.random().toString(36).slice(2)}.webp` const filePath = `${tmpFolder}/${fileName}` await fs.promises.writeFile(filePath, fileBuffer) const exec = util.promisify(cp.exec).bind(cp) await exec(`convert ${filePath} ${filePath.replace('.webp', '.gif')}`) if (/gif/.test(req.path)) return res.send(`https://${req.get('host')}/file/${fileName.replace('.webp', '.gif')}`) await exec(`ffmpeg -i ${filePath.replace('.webp', '.gif')} -movflags faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" ${filePath.replace(/.webp|.gif/g, '')}.mp4`) res.send(`https://${req.get('host')}/file/${fileName.replace('.webp', '.mp4')}`) } catch (e) { console.log(e) e = String(e) res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e }) } }) app.get('/fetch', async (req, res) => { try { if (!req.query.url) return res.json({ message: 'Required an url' }) let json = await axios.get(req.query.url) res.json(json.data) } catch (e) { res.send(e) } }) app.all(['/enhance', '/hd', '/upscale'], async (req, res) => { if (!['GET', 'POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' }) try { const { url } = req.method !== 'GET' ? req.body : req.query if (!url) return res.json({ success: false, message: 'Required parameter url' }) const result = await enhanceImage(url) res.json({ success: true, result }) } catch (e) { console.log(e) e = String(e) res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e }) } }) app.all('/animelast', async (req, res) => { const result = await scrapeAnimeInfo(); res.json({ creator: '@Kyouka', message: 'Success', uptime: new Date(process.uptime() * 1000).toUTCString().split(' ')[4], result }); }); app.all('/dood', async (req, res) => { const { url } = req.query if (!url) return res.json({ success: false, message: 'Required parameter url' }) const result = await kyou.execWithArgs(url) res.json({ creator: '@Kyouka', message: 'Success', uptime: new Date(process.uptime() * 1000).toUTCString().split(' ')[4], result }); }); app.get('/igstalk', async (req, res) => { try { if (!req.query.user) return res.json({ message: 'Required an username' }) let result = await igStalk(req.query.user) res.json({ result }) } catch (e) { res.send(e) } }) app.all('/stablediff/illusion', async (req, res) => { if (!['GET', 'POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' }) try { const { prompt, negative_prompt = 'low quality', image_url, num_inference_steps = 25, controlnet_conditioning_scale = 1 } = req.method !== 'GET' ? req.body : req.query if (!(prompt && image_url)) return res.json({ success: false, message: 'Required parameter prompt & image_url' }) const headers = { 'Content-Type': 'application/json', Authorization: `Key ${process.env.falAIKey}` } const { detail, response_url } = await (await fetch('https://54285744-illusion-diffusion.gateway.alpha.fal.ai/fal/queue/submit', { method: 'POST', body: JSON.stringify({ prompt, negative_prompt, image_url, num_inference_steps, controlnet_conditioning_scale }), headers })).json() if (detail) return res.json({ success: false, message: detail }) let retry = 0 while (true) { await new Promise(resolve => setTimeout(resolve, 2500)) const prediction = await (await fetch(response_url, { headers })).json() console.log(prediction) if (retry > 10) return res.json({ success: false, message: prediction.detail || 'Max retry has reached' }) if (prediction.image) return res.json({ success: true, result: prediction }) retry += 1 } } catch (e) { console.log(e) e = String(e) res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e }) } }) app.get('/dongo', async (req, res) => { const { url } = req.query if (!url) return res.json({ success: false, message: 'Required parameter url' }) const browser = await playwright.chromium.launch({ headless: true, executablePath: '/usr/bin/chromium', args: ['--no-sandbox'] }) const context = await browser.newContext({ extraHTTPHeaders: { 'accept': '*/*', 'accept-language': 'en-US,en;q=0.9,id;q=0.8', 'cache-control': 'no-cache', 'origin': url, 'pragma': 'no-cache', 'referer': url, 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'script', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'cross-site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' } }); const page = await context.newPage(); await page.goto(url); const content = await page.content(); // Get the page content as HTML await browser.close(); res.send(content); // Send the page content as response }); app.get('/fetch-page', async (req, res) => { const targetUrl = req.query.url; if (!targetUrl) { return res.status(400).json({ developer: "KyoukaDev", status: false, message: 'Parameter "url" dibutuhkan', }); } const baseUrl = new URL(targetUrl).origin; const browser = await playwright.chromium.launch({ headless: true, executablePath: '/usr/bin/chromium', // pastikan path ini valid args: ['--no-sandbox'] }); const context = await browser.newContext({ extraHTTPHeaders: { 'accept': '*/*', 'accept-language': 'en-US,en;q=0.9,id;q=0.8', 'cache-control': 'no-cache', 'origin': baseUrl, 'pragma': 'no-cache', 'referer': baseUrl, 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'script', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'cross-site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' } }); try { const page = await context.newPage(); await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 60000 }); await page.waitForTimeout(8000); const content = await page.content(); res.json({ developer: "KyoukaDev", status: true, data: { results: [ { content } ] } }); } catch (err) { res.status(500).json({ developer: "KyoukaDev", status: false, message: 'Gagal fetch halaman', error: err.message }); } finally { await browser.close(); } }); const PORT = process.env.PORT || 7860 app.listen(PORT, () => console.log('App running on port', PORT)) function formatSize(num) { return bytes(+num || 0, { unitSeparator: ' ' }) } function isBase64(str) { try { return btoa(atob(str)) === str } catch { return false } } function toPDF(urls) { return new Promise(async (resolve, reject) => { try { if (!Array.isArray(urls)) urls = [urls] const doc = new PDFDocument({ margin: 0, size: 'A4' }) const buffers = [] for (let i = 0; i < urls.length; i++) { const response = await fetch(urls[i], { headers: { referer: urls[i] }}) if (!response.ok) continue const type = response.headers.get('content-type') if (!/image/.test(type)) continue let buffer = Buffer.from(await response.arrayBuffer()) if (/gif|webp/.test(type)) buffer = await sharp(buffer).png().toBuffer() doc.image(buffer, 0, 0, { fit: [595.28, 841.89], align: 'center', valign: 'center' }) if (urls.length !== i + 1) doc.addPage() } doc.on('data', (chunk) => buffers.push(chunk)) doc.on('end', () => resolve(Buffer.concat(buffers))) doc.on('error', reject) doc.end() } catch (e) { console.log(e) reject(e) } }) } async function scrapeAnimeInfo() { try { const browser = await playwright.chromium.launch({ headless: true, executablePath: '/usr/bin/chromium', args: ['--no-sandbox'] }); const page = await browser.newPage(); await page.goto('http://66.29.129.161/?filter=latest&cat=1'); const pageContent = await page.content(); console.log(pageContent); // Wait for the list of videos to load await page.waitForSelector('.videos-list'); // Extract data from all articles const videoData = await page.$$eval('.videos-list article', articles => { return articles.map(article => { const thumbnail = article.querySelector('.post-thumbnail img').src; const title = article.querySelector('header.entry-header span').textContent; const url = article.querySelector('a').href; const duration = article.querySelector('.duration').textContent.trim(); return { thumbnail, title, url, duration }; }); }); await browser.close(); return videoData; } catch (error) { console.error('An error occurred during scraping:', error); return []; // Return an empty array in case of error } } async function enhanceImage(url) { const browser = await playwright.chromium.launch({ headless: true, executablePath: '/usr/bin/chromium', args: ['--no-sandbox'] }) const page = await browser.newPage() await page.goto('https://snapedit.app/id/enhance/upload') await page.waitForLoadState('domcontentloaded') const arrayBuffer = await (await fetch(url)).arrayBuffer() page.on('filechooser', (fileChooser) => { const fileObject = { name: 'file.jpg', mimeType: 'image/jpg', buffer: Buffer.from(arrayBuffer) } fileChooser.setFiles([fileObject]) }) await page.getByRole('button', { name: 'Unggah gambar', exact: true }).click() const response = await page.waitForResponse(res => { console.log(res.url()) return res.url().includes('api/enhance/v1') }, { timeout: 60 * 1000 }) const json = await response.json() await browser.close() return json } async function igStalk(user) { const getDetailPost = async url => { let html = (await axios.get(url, { headers: { 'Referer': 'https://www.picuki.com/', 'User-Agent': fakeua.mobile() }})).data let $ = cheerio.load(html), obj = {} obj.caption = $('title').text().trim().split(' Instagram post ')[1].split(' - Picuki.com')[0] obj.ago = $('div.single-photo-info').find('div.single-photo-time').text() obj.likes = $('div.info-bottom').find('span.icon-thumbs-up-alt').text() obj.comments = $('div.info-bottom').find('span.icon-chat').text() obj.url = $('div.single-photo.owl-carousel.owl-theme > div.item').get().map((x) => $(x).find('img').attr('src') || $(x).find('video').attr('src')) if (!obj.url.length) obj.url = [$('div.single-photo').find('img').attr('src') || $('div.single-photo').find('video').attr('src')] return obj } let html = (await axios.get('https://www.picuki.com/profile/' + user, { headers: { 'Referer': 'https://www.picuki.com/', 'User-Agent': fakeua.mobile() }})).data let $ = cheerio.load(html), obj = {}, arr = [] let urlPost = $('div.content > ul > li').get().map((x) => $(x).find('a').attr('href')) for (let x of urlPost) { if (x) arr.push(await getDetailPost(x)) } obj.avatar = $('div.profile-avatar').find('a').attr('href') obj.username = $('div.profile-name > h1').text() obj.fullname = $('div.profile-name > h2').text() obj.description = $('div.profile-description').text().trim() obj.followers = $('div.content-title').find('span.followed_by').text() obj.following = $('div.content-title').find('span.follows').text() obj.post = arr return obj }