forked from hankmander/screenshooter
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathshoot.js
164 lines (148 loc) · 4.28 KB
/
shoot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env node
const _ = require('lodash');
const async = require('async');
const http = require('http');
const puppeteer = require('puppeteer');
const url = require('url');
const fs = require('fs');
const defaultOptions = {
imageWidth: 240,
imageHeight: 240,
imageFormat: 'jpg',
browserWidth: 1024,
browserHeight: 1024,
gravity: 'North',
trim: false,
};
const VERBOSE_LOGGING = (process.env['VERBOSE_LOGGING'] === 'false' ? false : true);
let requestsBeingProcessed = 0;
const requestQueue = [];
let workingOnQueue = false;
let browser;
// Take URL, deliver image buffer
const renderUrlToImage = (url, imageOptions, callback) => {
let renderImageFormat;
if (imageOptions.imageFormat === 'jpg') {
renderImageFormat = 'jpeg';
}
else if (imageOptions.imageFormat) {
renderImageFormat = imageOptions.imageFormat.toLowerCase();
}
(async () => {
const page = await browser.newPage();
page.on("pageerror", function(err) {
console.log("Page error: " + err.toString());
page.close();
});
page.on("error", function(err) {
console.log("Error: " + err.toString());
page.close();
});
page.setViewport({
width: parseInt(imageOptions.browserWidth),
height: parseInt(imageOptions.browserHeight)
});
await page.goto(url, {waitUntil: 'networkidle2'});
const screenshot = await page.screenshot({
type: renderImageFormat
});
page.close();
return screenshot;
})().then(screenshot => {
callback(null, screenshot);
});
};
// Save image to disk
const saveImageBufferToDisk = (fileName, imageBuffer, callback) => {
console.log('Saving to disk:', fileName);
fs.writeFile(fileName, imageBuffer, 'binary', callback);
};
// Take a request object and work on it
const processHTTPRequest = (req, res, callback) => {
const pageURL = req.url.slice(1);
const imageOptions = _.merge({}, defaultOptions);
_.merge(imageOptions, url.parse(req.url, true).query);
if (!pageURL.includes('http')) {
// No URL
if (callback) callback('Not valid URL');
}
else {
requestsBeingProcessed++;
console.log('Working on: %s (total %d)', pageURL, requestsBeingProcessed);
renderUrlToImage(pageURL, imageOptions, (err, imageBuffer) => {
requestsBeingProcessed--;
console.log('Done with: %s (total %d)', pageURL, requestsBeingProcessed);
if (!err) {
res.writeHead(200, {
'Content-Type': `image/${imageOptions.imageFormat}`,
'Content-Length': imageBuffer.length,
'Cache-Control': 'public, max-age=31536000'});
res.end(imageBuffer);
}
else {
console.log('Image render error:', err);
if (res.send)
res.send(500);
else
res.end();
}
if (callback) callback(err);
});
}
};
// Process the incoming request if not already processing
// Else put into queue
const onIncomingHTTPRequest = (req, res) => {
console.log('Incoming request:', req.url);
processHTTPRequest(req, res); // Process immediately
};
const processCommandLine = () => {
const imageOptions = _.merge({}, defaultOptions);
async.waterfall([
cbWaterfall => {
for (let i = 2; i < process.argv.length; i++) {
const arg = process.argv[i];
if (arg.includes('http')) {
imageOptions.url = arg;
}
else if (arg.includes('=')) {
const param = arg.split('=');
imageOptions[param[0]] = param[1];
}
else if (arg.includes('.')) {
imageOptions.fileName = arg;
}
};
imageOptions.fileName = imageOptions.fileName || `screenshot.${imageOptions.imageFormat}`;
cbWaterfall(null, imageOptions);
},
(imageOptions, cbWaterfall) => {
console.log('Render URL to image', imageOptions);
renderUrlToImage(imageOptions.url, imageOptions, cbWaterfall);
},
(imageBuffer, cbWaterfall) => {
saveImageBufferToDisk(imageOptions.fileName, imageBuffer, cbWaterfall);
},
]
);
};
// Start server
const startWebServer = () => {
const serverPort = process.env.PORT || 1337;
const server = http.createServer(onIncomingHTTPRequest);
server.listen(serverPort, () => {
console.log(`Screenshooter service running on http://localhost:${serverPort}`);
});
};
// Main loop
if (process.argv.length >= 3) {
// Run as command line
processCommandLine();
}
else {
// Else web server after starting browser
(async () => {
browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
startWebServer();
})();
}