Browse Source

Initial project setup

pull/6/head
deam 5 years ago
commit
d6e9b7085f
  1. 2
      .gitignore
  2. 21
      LICENSE
  3. 10
      README.md
  4. 19
      chromium.js
  5. 5
      dev.js
  6. 16
      now.json
  7. 14
      package.json
  8. BIN
      public/favicon.ico
  9. 27
      public/index.html
  10. 30
      screenshot.js
  11. 25
      validator.js

2
.gitignore

@ -0,0 +1,2 @@
node_modules
package-lock.json

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Deam
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

10
README.md

@ -0,0 +1,10 @@
# Webshot
Screenshot websites as a service.
The images are getting cached for 1 minute and only the first load takes some time to process.
## Use cases
- You could use this as a preview image for your website in `og:image` or `twitter:image`
## Credits
- https://github.com/styfle/screenshot-v2

19
chromium.js

@ -0,0 +1,19 @@
const chrome = require('chrome-aws-lambda')
const puppeteer = require('puppeteer-core')
async function getScreenshot(url, type, quality, fullPage) {
const browser = await puppeteer.launch({
args: chrome.args,
executablePath: await chrome.executablePath,
headless: chrome.headless,
})
const page = await browser.newPage()
await page.setViewport({ width: 1920, height: 1080, deviceScaleFactor: 1 })
await page.goto(url)
const file = await page.screenshot({ type, quality, fullPage })
await browser.close()
return file
}
module.exports = { getScreenshot }

5
dev.js

@ -0,0 +1,5 @@
const { createServer } = require('http')
const PORT = 1234
const handleServer = require('./screenshot')
const handleListen = () => console.log(`Listening on ${PORT}...`)
createServer(handleServer).listen(PORT, handleListen)

16
now.json

@ -0,0 +1,16 @@
{
"name": "webshot",
"version": 2,
"builds": [
{ "src": "public/*", "use": "@now/static" },
{
"src": "screenshot.js",
"use": "@now/node",
"config": { "maxLambdaSize": "40mb" }
}
],
"routes": [
{ "src": "/", "dest": "/public/index.html" },
{ "src": "/(.+)", "dest": "/screenshot.js" }
]
}

14
package.json

@ -0,0 +1,14 @@
{
"name": "webshot",
"version": "1.0.0",
"description": "Take screenshot of website",
"main": "dev.js",
"scripts": {
"dev": "node dev.js"
},
"license": "MIT",
"dependencies": {
"chrome-aws-lambda": "^1.11.1",
"puppeteer-core": "^1.11.0"
}
}

BIN
public/favicon.ico

27
public/index.html

@ -0,0 +1,27 @@
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<title>Screenshot as a service</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<h1>Screenshot as a service</h1>
<p>Please provide a path to a website or choose one of the following:</p>
<ul>
<li><a href="/google.com">/google.com</a></li>
<li><a href="/zeit.co/blog?type=png">/zeit.co/blog?type=png</a></li>
<li>
<a href="/zeit.co/about?fullPage=true">/zeit.co/about?fullPage=true</a>
</li>
<li>
<a href="/stripe.com?fullPage=true">/zeit.co/about?fullPage=true</a>
</li>
<li>
<a href="/ceriously.com?type=jpeg&quality=75&fullPage=true"
>/ceriously.com?type=jpeg&quality=75&fullPage=true</a
>
</li>
</ul>
</body>
</html>

30
screenshot.js

@ -0,0 +1,30 @@
const { parse } = require('url')
const { getScreenshot } = require('./chromium')
const { getInt, getUrlFromPath, isValidUrl } = require('./validator')
module.exports = async function(req, res) {
try {
const { pathname = '/', query = {} } = parse(req.url, true)
const { type = 'png', quality, fullPage } = query
const url = getUrlFromPath(pathname)
const qual = getInt(quality)
if (!isValidUrl(url)) {
res.statusCode = 400
res.setHeader('Content-Type', 'text/html')
res.end(
`<h1>Bad Request</h1><p>The url <em>${url}</em> is not valid.</p>`
)
} else {
const file = await getScreenshot(url, type, qual, fullPage)
res.statusCode = 200
res.setHeader('Content-Type', `image/${type}`)
res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate')
res.end(file)
}
} catch (e) {
res.statusCode = 500
res.setHeader('Content-Type', 'text/html')
res.end('<h1>Server Error</h1><p>Sorry, there was a problem</p>')
console.error(e.message)
}
}

25
validator.js

@ -0,0 +1,25 @@
const { URL } = require('url')
function getInt(str) {
return /[0-9]+/.test(str) ? parseInt(str) : undefined
}
function getUrlFromPath(str) {
let url = str.slice(1)
if (!url.startsWith('http')) {
return 'https://' + url
}
return url
}
function isValidUrl(str) {
try {
const url = new URL(str)
return url.hostname.includes('.')
} catch (e) {
console.error(e.message)
return false
}
}
module.exports = { getInt, getUrlFromPath, isValidUrl }
Loading…
Cancel
Save