Skip to content

Commit

Permalink
Device name, cookie, user-agent support
Browse files Browse the repository at this point in the history
  • Loading branch information
mixu committed Oct 14, 2015
1 parent 3b7c7c8 commit e00c31f
Show file tree
Hide file tree
Showing 14 changed files with 429 additions and 129 deletions.
8 changes: 8 additions & 0 deletions Makefile
@@ -0,0 +1,8 @@
GJSLINT := --nojsdoc --exclude_directories=node_modules --exclude_files=bin/shot.js --max_line_length=120 --disable=200,201,202,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,230,231,232,233,250,251,252

lint:
fixjsstyle $(GJSLINT) -r .
gjslint $(GJSLINT) -r .
jshint --exclude node_modules .

.PHONY: lint
8 changes: 4 additions & 4 deletions bin/shot.js
Expand Up @@ -17,7 +17,7 @@ var defaultOptions = require('../lib/default-options.js'),
var argv = xtend({}, defaultOptions, subarg(process.argv.slice(2)));

if (argv.v || argv.version) {
console.log('shot v'+ require('../package.json').version);
console.log('shot v' + require('../package.json').version);
spawn(electron, [__dirname + '/../electron/index.js', '--version'], { stdio: 'inherit' });
return;
}
Expand Down Expand Up @@ -62,7 +62,7 @@ if (pairs.length > 0) {
pairs.forEach(function(pair) {
app.use(pair[0], express.static(pair[1]));
});
server = app.listen(argv.port, function () {
server = app.listen(argv.port, function() {
console.log('Express server listening at ' + baseUrl);
runElectron();
});
Expand All @@ -78,7 +78,7 @@ function runElectron() {
return typeof defaultOptions[key] === 'undefined' && key !== '_';
}).reduce(function(all, key) {
if (typeof argv[key] !== 'boolean') {
return all.concat([ '--' + key, argv[key] ]);
return all.concat(['--' + key, argv[key]]);
} else {
return all.concat('--' + (argv[key] ? 'no-' : '') + key);
}
Expand All @@ -91,7 +91,7 @@ function runElectron() {

child.stdin.end(JSON.stringify(tasks));

child.on('close', function (code) {
child.on('close', function(code) {
console.log('Electron exited');
if (server) {
server.close();
Expand Down
28 changes: 19 additions & 9 deletions bin/usage.txt
@@ -1,6 +1,6 @@
USAGE

shot [options] [url(s)] [resolution(s)]
shot [options] [url(s)] [resolution(s)|device(s)]

URL EXAMPLES

Expand All @@ -10,14 +10,26 @@ URL EXAMPLES
./some/file.html Captures a local files by mounting `./some` under localhost using a HTTP server,
/some/file.html and then requesting `/file.html`.

RESOLUTION EXAMPLES
RESOLUTION / DEVICE EXAMPLES

1024x768 Captures a screenshot which is cropped to 1024px width and 768px height.

1024x Captures a screenshot which is 1024px wide, and as tall needed for the page.

1024 Same as above.

"Apple iPhone 6" Captures a screenshot which is as wide as a vertical iPhone 6 and as tall as needed,
with device pixel resolution and pixel ratio emulation
(e.g. CSS / JS screen dimension queries work).

"horizontal Apple iPhone 6" Captures a screenshot which is as wide as a horizontal iPhone 6,
and as tall as needed, with device pixel resolution emulation

"cropped Apple iPhone 6" Captures a screenshot which is as wide and tall as a single screen on
a vertical iPhone 6.

"cropped horizontal Apple iPhone 6" Both cropped and horizontal.

OPTIONS - CAPTURE

--out <dir> Write the screenshots to a specific directory (default: process.cwd)
Expand All @@ -34,6 +46,11 @@ OPTIONS - CAPTURE

--zoom-factor <n> The default zoom factor of the page; e.g. 1.0 represents 100% and 3.0 represents 300%.

OPTIONS - HTTP

--user-agent <string> Sets a custom user agent string.

--cookie <cookie> Sets a custom cookie. Can be set multiple times.

OPTIONS - SERVER

Expand Down Expand Up @@ -77,9 +94,6 @@ TODO

file://... Captures a local file by loading the file URL directly, without a static file server.

--user-agent <string> Sets a custom user agent string.

--cookie <cookie> Sets a custom cookie. Can be set multiple times.

OPTIONS - NETWORK EMULATION

Expand All @@ -91,10 +105,6 @@ OPTIONS - NETWORK EMULATION

--upload <Bps> Upload rate in Bps

OPTIONS - DEVICE EMULATION

--emulate-device <device>


OPTIONS - CONTENT INJECTION

Expand Down
8 changes: 4 additions & 4 deletions electron/preload.js
Expand Up @@ -17,14 +17,13 @@ function waitFor(num, onDone) {
}
ipc.on('ensure-rendered', function ensureRendered(delay, eventName) {
console.log('RECEIVE', 'ensure-rendered');

try {
var style = document.createElement('style');
// WebKit hack :(
style.appendChild(document.createTextNode(''));
document.head.appendChild(style);
style.sheet.insertRule('::-webkit-scrollbar { display: none; }');
} catch(e) {}
} catch (e) {}

waitFor(delay, function() {
console.log('SEND', eventName);
Expand All @@ -34,9 +33,10 @@ ipc.on('ensure-rendered', function ensureRendered(delay, eventName) {

ipc.on('get-dimensions', function ensureRendered(selector) {
console.log('get-dimensions', selector);
var result;
try {
var result = document.querySelector(selector).getBoundingClientRect();
} catch(e) {
result = document.querySelector(selector).getBoundingClientRect();
} catch (e) {
console.error('Could not find target ' + selector, e);
ipc.send('return-dimensions', false);
return;
Expand Down
11 changes: 1 addition & 10 deletions electron/run-tasks.js
Expand Up @@ -7,16 +7,7 @@ module.exports = function(tasks) {
return function(done) {
console.log(task);

targetWindow.initialize({
width: task.size.width,
height: task.size.height || 768,
url: task.url,
out: task.out,
format: task.format,
quality: task.quality,
delay: task.delay,
'zoom-factor': task['zoom-factor'],
}, function() {
targetWindow.initialize(task, function() {
if (task.selector) {
targetWindow.getDimensions(task.selector, function(dims) {
targetWindow.capture(dims, done);
Expand Down
73 changes: 44 additions & 29 deletions electron/target-window.js
Expand Up @@ -10,9 +10,9 @@ function TargetWindow() {
}

// sync initialization
TargetWindow.prototype.initialize = function(opts, onDone) {
TargetWindow.prototype.initialize = function(task, onDone) {
var self = this;
this.opts = opts;
this.task = task;
if (!this.window) {
this.window = new BrowserWindow({
show: true,
Expand All @@ -37,57 +37,72 @@ TargetWindow.prototype.initialize = function(opts, onDone) {
}

// width, height
this.window.setContentSize(opts.width, opts.height);
this.window.setContentSize(task.size.width, task.size.height || 768);

ipc.once('window-loaded', function() {
console.log('IPC', 'window-loaded');
console.log('SEND', 'ensure-rendered');

// webContents configuration
// - zoom factor
if (opts['zoom-factor'] !== 1) {
console.log('SEND', 'set-zoom-factor', opts['zoom-factor']);
self.window.webContents.send('set-zoom-factor', opts['zoom-factor']);
if (task['zoom-factor'] !== 1) {
console.log('SEND', 'set-zoom-factor', task['zoom-factor']);
self.window.webContents.send('set-zoom-factor', task['zoom-factor']);
}

ipc.once('loaded', function() {
console.log('IPC', 'loaded');
onDone();
});
self.window.webContents.send('ensure-rendered', opts.delay, 'loaded');
self.window.webContents.send('ensure-rendered', task.delay, 'loaded');
});

this.window.setContentSize(375, 627);
// useful: set the size exactly (contentsize is not useful here)
this.window.setSize(375, 627);
this.window.setMaximumSize(627, 627);
if (task.device) {
// useful: set the size exactly (contentsize is not useful here)
this.window.setSize(task.size.width, task.size.height);
this.window.setMaximumSize(task.size.width, task.size.height);
}

this.window.loadUrl(opts.url, {
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4'
});

this.window.loadUrl(task.url, task['user-agent'] !== '' ? { userAgent: task['user-agent'] } : {});
// this happens before the page starts executing
self.window.webContents.enableDeviceEmulation({
screenPosition: 'mobile',
screenSize: { width: 375, height: 627 },
viewPosition: { x: 0, y: 0 },
offset: {x: 0, y: 0},
viewSize: { width: 375, height: 627 },
deviceScaleFactor: 2,
fitToView: false,
scale: 1,
});
if (task.device) {
this.window.webContents.enableDeviceEmulation(task.device);
}

if (task.cookies) {
// TODO wait
task.cookies.forEach(function(cookie) {
console.log('Set cookie', cookie);
self.window.webContents.session.cookies.set(cookie, function(err) {
if (err) {
console.log('ERR Set cookie', cookie, err);
}
});
});
}

// to work around https://github.com/atom/electron/issues/1580
this.window.webContents.executeJavaScript(fs.readFileSync(path.resolve(__dirname + '/preload.js'), 'utf8'));

};

TargetWindow.prototype.reset = function() {
var self = this;
// reset zoom
if (this.opts['zoom-factor'] !== 1) {
if (this.task['zoom-factor'] !== 1) {
this.window.webContents.send('set-zoom-factor', 1);
}
// reset deviceEmulation
if (this.task.device) {
this.window.webContents.disableDeviceEmulation();
}
// reset cookies
if (this.task.cookies) {
// TODO wait
this.task.cookies.forEach(function(cookie) {
self.window.webContents.session.cookies.remove(cookie, function() {});
});
}
};

TargetWindow.prototype.getDimensions = function(selector, onDone) {
Expand All @@ -101,7 +116,7 @@ TargetWindow.prototype.capture = function(dims, onDone) {
var self = this;
var tries = 0;
var hasDims = arguments.length > 1;
var opts = this.opts;
var task = this.task;

function tryCapture(dims) {
if (hasDims) {
Expand All @@ -122,8 +137,8 @@ TargetWindow.prototype.capture = function(dims, onDone) {
return;
}

console.log('write screenshot', opts.out);
fs.writeFile(opts.out, (opts.format === 'png' ? data.toPng() : data.toJpeg(opts.quality)));
console.log('write screenshot', task.out);
fs.writeFile(task.out, (task.format === 'png' ? data.toPng() : data.toJpeg(task.quality)));
self.reset();
onDone();
}
Expand Down

0 comments on commit e00c31f

Please sign in to comment.