devtools-timeline-images
Version:
Simple utility to transform exported Chrome devtools timeline json to images.
114 lines (100 loc) • 3.5 kB
JavaScript
const fs = require('fs-extra');
const inquirer = require('inquirer');
const chalk = require('chalk');
const path = require('path');
/**
* 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;
}
/**
* Check if provided input is valid.
* @param {string} input Path to the JSON file.
* @returns {boolean}
*/
function checkInput(input) {
if (!fs.existsSync(input)) {
throw new Error(`Provided file '${input}' doesn't exist`);
}
return true;
}
/**
* Check if the provided output is valid. Output can be a folder or a file based on the command.
* @param {string} output
* @param {boolean} [isFile=false] If the output is a file or directory
* @returns {Promise<boolean>}
*/
async function checkOutput(output, isFile = false) {
if (isFile) {
if (path.extname(output) === '') throw new Error(`Provided output '${output}' is not a file`);
if (!fs.existsSync(path.dirname(output))) throw new Error(`Provided output path '${path.dirname(output)}' doesn't exist`);
return true;
}
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);
}
return true;
}
/**
* Return all screenshots from Chrome Timeline JSON file.
* @param {string} data
* @returns {string[]} Array of base64 strings.
*/
function exportImagesFromChromeTimeline(data) {
let jsonData;
try {
jsonData = JSON.parse(data);
} 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);
}
return jsonData.filter(item => item.name === 'Screenshot').map(item => item.args.snapshot);
}
module.exports = {
getFileTypeFromStream,
checkInput,
checkOutput,
exportImagesFromChromeTimeline,
};