Skip to content

Commit

Permalink
Merge pull request #8 from ilicmarko/v2
Browse files Browse the repository at this point in the history
V2
  • Loading branch information
ilicmarko committed May 12, 2019
2 parents 27a90de + a955cd3 commit ae9cd03
Show file tree
Hide file tree
Showing 7 changed files with 719 additions and 78 deletions.
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

A really small utility to extract images from Chrome Timeline.

## Setup
## Installation

```bash
yarn global add devtools-timeline-images
Expand All @@ -16,16 +16,33 @@ npm i -g devtools-timeline-images

## Usage

CLI takes to arguments `-i` and `-o`:
* `-i` or `--input` - Specify the input JSON file.
* `-o` or `--output` - Specify the output folder.
As of v2 CLI includes and alias for the name, `dte` (Devtools Timeline Export). This has been changed as in the future
there is a plan to export videos, not only images.

### Image

```bash
dte images <input> [options]

Generate sequence of images.

Options:
--version Show version number [boolean]
--output, -o Path to JSON file generated by Chrome. [string] [required]
-h, --help Show help [boolean]
```

Also you can generate images with an alias `i`, like this: `dte i <input> [options]`.

## Options
- `-o` or `--output` - Specify the output folder.

*Note: If the output directory does not exist the CLI will create it.*

## Example

```bash
devtools-timeline-images -i ./example-site.json -o ./images
dte i ./example-site.json -o ./images
```

## Save a recoding
Expand Down
67 changes: 0 additions & 67 deletions index.js

This file was deleted.

86 changes: 86 additions & 0 deletions lib/commands/images.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const fs = require('fs-extra');
const chalk = require('chalk');
const path = require('path');
const utils = require('../utils');
const inquirer = require('inquirer');

exports.command = 'images <input>';
exports.aliases = ['i'];
exports.desc = 'Generate sequence of images.';
exports.builder = {
output: {
type: 'string',
aliases: ['o'],
describe: 'Path to JSON file generated by Chrome.',
demand: true,
normalize: true,
}
};
exports.handler = async (argv) => {
const { input, output } = argv;

if (!fs.existsSync(input)) {
console.error(chalk.red(`Provided file '${input}' doesn't exist`));
process.exit(1);
}

if (!fs.existsSync(output)) {
try {
fs.mkdirSync(output);
console.log(chalk.blue(`Directory ${output} created!`));
} catch (err) {
if (err.code === 'ENOENT') {
throw new Error(`EACCES: permission denied, mkdir '${output}'`);
}

throw err;
}
} else {
const { overwrite } = await inquirer
.prompt([{
name: 'overwrite',
type: 'confirm',
message: `Directory \`${output}\` already exists. Do you want to overwrite it?`
}]);

if (overwrite) fs.emptyDirSync(output);
}

const fileData = fs.readFileSync(input, 'utf8');
let jsonData;

try {
jsonData = JSON.parse(fileData);
} catch (e) {
console.error(chalk.red(e));
process.exit(1)
}

if (!Array.isArray(jsonData)) {
console.log('This doesn\'t look like Chrome Timeline JSON. Please provide valid data.');
process.exit(1);
}

const snapshots = jsonData.filter(item => item.name === 'Screenshot').map(item => item.args.snapshot);

if (!snapshots.length) {
console.error(chalk.red('There are no captured frames inside the provided input.'));
process.exit(1);
}

let imageStream;
let ext;

snapshots.forEach((snapshot, i) => {
imageStream = Buffer.from(snapshot, 'base64');
ext = utils.getFileTypeFromStream(imageStream);
if (ext) {
fs.writeFileSync(path.resolve(output, `${i}.${ext}`), imageStream);
} else {
console.log(chalk.yellow(`Frame ${i} couldn't be saved.`))
}
});

console.log(chalk.green.bold(`${snapshots.length} frames exported to ${output}`));
process.exit();
};
18 changes: 18 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node
const path = require('path');
const yargs = require('yargs');

// noinspection BadExpressionStatementJS
yargs
.scriptName('dte')
.usage('$0 <cmd> [args]')
.commandDir(path.join(__dirname, 'commands'))
.demandCommand()
.option('output', {
alias: 'o',
describe: 'Output folder where the images will be exported.'
})
.demandOption(['output'], 'Please provide output argument.')
.help('h')
.alias('h', 'help')
.argv;
34 changes: 34 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Check Buffer for file signature.
* @param {Array} header
* @param {ArrayBuffer} stream
* @param {Object} [settings]
* @returns {boolean}
*/
function checkHeader(header, stream, settings) {
// Basic early checks if the stream is a Buffer
if (!(stream instanceof Uint8Array || stream instanceof ArrayBuffer || Buffer.isBuffer(stream))) throw new Error('Buffer not valid');
const buffer = stream instanceof Uint8Array ? stream : new Uint8Array(input);
if (!(buffer && buffer.length > 1)) throw new Error('Buffer not valid');

const defaultSettings = { offset: 0 };
const mergedSettings = { ...defaultSettings, ...settings };

for (let i = 0; i < header.length; i++) {
if (header[i] !== buffer[i + mergedSettings.offset]) {
return false;
}
}
return true;
}

function getFileTypeFromStream(stream) {
if (checkHeader([0xFF, 0xD8, 0xFF], stream)) return 'jpg';
if (checkHeader([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A], stream)) return 'png';
if (checkHeader([0x57, 0x45, 0x42, 0x50], stream, {offset: 8})) return 'webp';
return false;
}

module.exports = {
getFileTypeFromStream,
};
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"name": "devtools-timeline-images",
"version": "1.0.3",
"description": "Simple utility to transform exported Chrome devtools timeline json to images. ",
"main": "index.js",
"main": "lib/index.js",
"files": [
"/lib"
],
"repository": "git@github.com:ilicmarko/devtools-timeline-images.git",
"author": "Marko Ilic <ilic.marko.05@live.com>",
"license": "MIT",
Expand All @@ -15,10 +18,13 @@
],
"homepage": "https://github.com/ilicmarko/devtools-timeline-images#readme",
"bin": {
"devtools-timeline-images": "index.js"
"devtools-timeline-images": "lib/index.js",
"dte": "lib/index.js"
},
"dependencies": {
"chalk": "^2.4.2",
"minimist": "^1.2.0"
"fs-extra": "^8.0.0",
"inquirer": "^6.3.1",
"yargs": "^13.2.2"
}
}
Loading

0 comments on commit ae9cd03

Please sign in to comment.