|
const express = require('express'); |
|
const puppeteer = require('puppeteer-extra'); |
|
const StealthPlugin = require('puppeteer-extra-plugin-stealth'); |
|
const AnonymizeUA = require('puppeteer-extra-plugin-anonymize-ua'); |
|
const QRCode = require('qrcode'); |
|
const Jimp = require('jimp'); |
|
const QrCodeReader = require('qrcode-reader'); |
|
|
|
puppeteer.use(StealthPlugin()); |
|
puppeteer.use(AnonymizeUA()); |
|
|
|
const app = express(); |
|
const port = 7860; |
|
|
|
app.use(express.json()); |
|
app.get('/', async (req, res) => { |
|
console.log('request to /') |
|
res.send('halo kontol') |
|
}) |
|
app.post('/screenshot', async (req, res) => { |
|
console.log('request to /screenshot') |
|
const { |
|
ua, |
|
url, |
|
type, |
|
width, |
|
height, |
|
language, |
|
fullpage |
|
} = req.body; |
|
if (!url) return res.send('please input url') |
|
await processScreenshot(req, res, { |
|
ua, |
|
url, |
|
type, |
|
width, |
|
height, |
|
language, |
|
fullpage |
|
}); |
|
}); |
|
|
|
app.get('/screenshot', async (req, res) => { |
|
console.log('request to /screenshot (get)') |
|
const { |
|
ua, |
|
url, |
|
type, |
|
width, |
|
height, |
|
language, |
|
fullpage |
|
} = req.query; |
|
if (!url) return res.send('please input url') |
|
await processScreenshot(req, res, { |
|
ua, |
|
url, |
|
type, |
|
width, |
|
height, |
|
language, |
|
fullpage |
|
}); |
|
}); |
|
app.get('/qrcode', async (req, res) => { |
|
try { |
|
const { |
|
mode, |
|
url |
|
} = req.query; |
|
|
|
if (!mode || !url) { |
|
return res.status(400).send('what?'); |
|
} |
|
|
|
if (mode === 'create') { |
|
|
|
QRCode.toDataURL(url, (err, src) => { |
|
if (err) return res.send({ |
|
error: 'Error generating QR code' |
|
}); |
|
res.type('png').send(Buffer.from(src.split(",")[1], "base64")); |
|
}); |
|
} else if (['read', 'scan'].includes(mode)) { |
|
|
|
const rts = await fetch(url); |
|
if (!rts.ok || rts.status !== 200) return res.send({ |
|
status: 400, |
|
message: 'Can\'t buffer url' |
|
}) |
|
if (!/image/.test(rts.headers.get('content-type'))) return res.send({ |
|
status: 400, |
|
message: 'Only image type' |
|
}) |
|
const buffer = Buffer.from(await rts.arrayBuffer()); |
|
const image = await Jimp.read(buffer); |
|
|
|
|
|
image |
|
.grayscale() |
|
.contrast(1) |
|
.normalize(); |
|
|
|
const qrCodeReader = new QrCodeReader(); |
|
|
|
qrCodeReader.callback = (err, value) => { |
|
if (err) return res.send({ |
|
error: 'Error reading QR code' |
|
}); |
|
res.json({ |
|
result: value.result |
|
}); |
|
}; |
|
|
|
const bitmap = image.bitmap; |
|
qrCodeReader.decode({ |
|
width: bitmap.width, |
|
height: bitmap.height, |
|
data: bitmap.data |
|
}); |
|
} else { |
|
QRCode.toDataURL(url, (err, src) => { |
|
if (err) return res.send({ |
|
error: 'Error generating QR code' |
|
}); |
|
res.type('png').send(Buffer.from(src.split(",")[1], "base64")); |
|
}); |
|
} |
|
} catch (error) { |
|
console.error(error); |
|
res.send({ |
|
error: 'Internal Server Error' |
|
}); |
|
} |
|
}); |
|
|
|
async function processScreenshot(req, res, { |
|
ua, |
|
url, |
|
type, |
|
width, |
|
height, |
|
language, |
|
fullpage |
|
}) { |
|
try { |
|
console.log('process screenshot') |
|
const browser = await puppeteer.launch({ |
|
headless: "new", |
|
args: ["--aggressive-tab-discard", |
|
"--disable-accelerated-2d-canvas", |
|
"--disable-application-cache", |
|
"--disable-cache", |
|
"--disable-dev-shm-usage", |
|
"--disable-gpu", |
|
"--disable-offline-load-stale-cache", |
|
"--disable-setuid-sandbox", |
|
"--disable-setuid-sandbox", |
|
"--disk-cache-size=0", |
|
"--ignore-certificate-errors", |
|
"--no-first-run", |
|
"--no-sandbox", |
|
"--no-zygote" |
|
] |
|
}); |
|
const page = await browser.newPage(); |
|
|
|
|
|
await page.setExtraHTTPHeaders({ |
|
'Accept-Language': language || 'id-ID', |
|
'User-Agent': ua || 'Mozilla/5.0 (Linux; Android 13; Pixel Build/RPB1.210523.001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36', |
|
}); |
|
|
|
await page.goto(url, { |
|
waitUntil: 'networkidle2', |
|
}); |
|
let full = fullpage == 1 ? true : false |
|
let screenshotOptions = { |
|
fullPage: true |
|
}; |
|
if (type === 'desktop') { |
|
screenshotOptions = { |
|
fullPage: full, |
|
width: 1280, |
|
height: 800 |
|
}; |
|
await page.setViewport({ |
|
width: 1280, |
|
height: 800, |
|
}); |
|
} else if (type === 'mobile') { |
|
screenshotOptions = { |
|
fullPage: full, |
|
width: 375, |
|
height: 667 |
|
}; |
|
await page.setViewport({ |
|
width: 375, |
|
height: 667, |
|
}); |
|
} else if (type === 'tablet') { |
|
screenshotOptions = { |
|
fullPage: full, |
|
width: 768, |
|
height: 1024 |
|
}; |
|
await page.setViewport({ |
|
width: 768, |
|
height: 1024, |
|
}); |
|
} else if (type === 'iphone') { |
|
screenshotOptions = { |
|
fullPage: full, |
|
width: 375, |
|
height: 667 |
|
}; |
|
await page.setViewport({ |
|
width: 375, |
|
height: 667, |
|
}); |
|
} else if (type === 'custom') { |
|
if (width && height > 4096) { |
|
return res.json({ |
|
"status": 400, |
|
"message": "Width and height values should not exceed 4096 pixels." |
|
}); |
|
await browser.close(); |
|
} |
|
if (width && height < 400) { |
|
return res.json({ |
|
"status": 400, |
|
"message": "Width and height values should not be less than 400 pixels." |
|
}); |
|
await browser.close(); |
|
} |
|
screenshotOptions = { |
|
fullPage: full, |
|
width: width || 375, |
|
height: height || 667 |
|
}; |
|
await page.setViewport({ |
|
width: Number(width) || 375, |
|
height: Number(height) || 667, |
|
}); |
|
} |
|
|
|
|
|
await page.waitForTimeout(3000); |
|
|
|
const screenshot = await page.screenshot(screenshotOptions); |
|
|
|
res.writeHead(200, { |
|
'Content-Type': 'image/png', |
|
'Content-Length': screenshot.length, |
|
}); |
|
res.end(screenshot); |
|
console.log('process done'); |
|
await browser.close(); |
|
} catch (e) { |
|
log(e) |
|
return res.json({ |
|
status: 400, |
|
message: 'error when take a screenshot' |
|
}) |
|
} |
|
} |
|
|
|
app.listen(port, () => { |
|
console.log(`Server is running on port ${port}`); |
|
}); |