|
const express = require('express'); |
|
const { chromium } = require('playwright'); |
|
const QRCode = require('qrcode'); |
|
const Jimp = require('jimp'); |
|
const QrCodeReader = require('qrcode-reader'); |
|
|
|
|
|
const app = express(); |
|
const port = 7860; |
|
|
|
|
|
let browser; |
|
let browserContext; |
|
|
|
app.use(express.json()); |
|
|
|
app.get('/', (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'); |
|
|
|
|
|
if (!browser) { |
|
browser = await chromium.launch({ |
|
headless: true, |
|
args: ["--no-sandbox", "--disable-setuid-sandbox"] |
|
}); |
|
} |
|
|
|
|
|
if (!browserContext) { |
|
browserContext = await browser.newContext({ |
|
userAgent: ua || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', |
|
viewport: { width: width || 1280, height: height || 800 }, |
|
deviceScaleFactor: 2 |
|
}); |
|
} |
|
|
|
const page = await browserContext.newPage(); |
|
|
|
if (language) { |
|
await page.emulateMedia({ colorScheme: language }); |
|
} |
|
|
|
await page.goto(url, { waitUntil: 'networkidle' }); |
|
|
|
|
|
await page.waitForLoadState('networkidle'); |
|
|
|
let screenshotOptions = { |
|
fullPage: fullpage == 1 ? true : false, |
|
type: 'png', |
|
omitBackground: false |
|
}; |
|
|
|
if (type === 'desktop') { |
|
await page.setViewportSize({ |
|
width: 1920, |
|
height: 1080, |
|
}); |
|
} else if (type === 'mobile') { |
|
await page.setViewportSize({ |
|
width: 375, |
|
height: 667, |
|
}); |
|
} else if (type === 'tablet') { |
|
await page.setViewportSize({ |
|
width: 768, |
|
height: 1024, |
|
}); |
|
} else if (type === 'iphone') { |
|
await page.setViewportSize({ |
|
width: 375, |
|
height: 667, |
|
}); |
|
} else if (type === 'custom') { |
|
if (width && height > 4096) { |
|
await page.close(); |
|
return res.json({ |
|
"status": 400, |
|
"message": "Width and height values should not exceed 4096 pixels." |
|
}); |
|
} |
|
if (width && height < 400) { |
|
await page.close(); |
|
return res.json({ |
|
"status": 400, |
|
"message": "Width and height values should not be less than 400 pixels." |
|
}); |
|
} |
|
await page.setViewportSize({ |
|
width: Number(width) || 375, |
|
height: Number(height) || 667, |
|
}); |
|
} |
|
|
|
await page.waitForTimeout(5000); |
|
|
|
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 page.close(); |
|
|
|
|
|
if (browserContext.pages().length > 10) { |
|
await browserContext.close(); |
|
browserContext = await browser.newContext(); |
|
} |
|
|
|
|
|
if (global.gc) { |
|
global.gc(); |
|
} |
|
} catch (e) { |
|
console.error(e); |
|
return res.json({ |
|
status: 400, |
|
message: 'error when take a screenshot' |
|
}); |
|
} |
|
} |
|
|
|
app.listen(port, () => { |
|
console.log(`Server is running on port ${port}`); |
|
}); |
|
|