-
Notifications
You must be signed in to change notification settings - Fork 3
/
puppeteer-gif-cast.js
160 lines (133 loc) · 4.41 KB
/
puppeteer-gif-cast.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
'use strict';
//A little setup ahead of time
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
let args = yargs(hideBin(process.argv))
.usage('$0 <url> <name>', 'starts capturing the gif at <url> and save it with <name>.gif', (yargs) => {
yargs.positional('url', {
describe: 'the url to caputre a scrolling gif from',
type: 'string'
})
.positional('name', {
describe: "the name of the final gif file",
type: "string"
})
})
.option('width', {
alias: 'w',
type: 'number',
description: 'Sets a width for the captured gif',
default: 768
})
.option('height', {
alias: 'h',
type: 'number',
description: 'Sets a height for the captured gif',
default: 600
})
.option('scroll', {
alias: 's',
type: 'number',
description: 'How far to scroll down the per frame',
default: 100
})
.option('duration', {
alias: 'd',
type: 'number',
description: 'Sets gif duration in seconds',
default: 60
})
.example([
['npm start http://example.com example', 'capture gif using default values and saves it as example.gif'],
['npm start http://example.com example -- --width 1080 --height 720', 'capture gif with custom dimensions'],
['npm start http://example.com example -- --duration 120', 'capture gif for 120 seconds']
])
.parse()
const { width, height, name, duration, url, scroll } = args;
const puppeteer = require('puppeteer');
const GIFEncoder = require('gif-encoder');
const fs = require('fs');
const getPixels = require('get-pixels');
const workDir = './temp/';
const gifDir = './gifs/';
if (!fs.existsSync(workDir)) {
fs.mkdirSync(workDir);
};
if (!fs.existsSync(gifDir)) {
fs.mkdirSync(gifDir);
};
let file = require('fs').createWriteStream(gifDir + name + '.gif');
// Setup gif encoder and parameters
const encoder = new GIFEncoder(width, height);
encoder.setFrameRate(60);
encoder.pipe(file);
encoder.setQuality(40);
encoder.setDelay(500);
encoder.writeHeader();
encoder.setRepeat(0);
// Function Declarations
function addToGif(images, counter = 0) {
getPixels(images[counter], function (err, pixels) {
encoder.addFrame(pixels.data);
encoder.read();
if (counter === images.length - 1) {
encoder.finish();
cleanUp(images, function (err) {
if (err) {
console.log(err);
} else {
fs.rmdirSync(workDir);
console.log('Gif created!');
process.exit(0);
}
});
} else {
addToGif(images, ++counter);
}
})
}
function cleanUp(listOfPNGs, callback) {
let i = listOfPNGs.length;
listOfPNGs.forEach(function (filepath) {
fs.unlink(filepath, function (err) {
i--;
if (err) {
callback(err);
return;
} else if (i <= 0) {
callback(null);
}
});
});
}
// This is where the magic happens:
(async () => {
console.info(`Capturing gif "${name}.gif" with following parameters:`)
console.info(`Origin URL: ${url}`)
console.info(`Width: ${width}`)
console.info(`Height: ${height}`)
console.info(`Duration: ${duration}`)
console.info(`Scroll length: ${scroll}\n`)
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setViewport({ width: width, height: height });
await page.goto(url);
async function scrollPage() {
await page.evaluate(async (scrollLength) => {
window.scrollBy(0, scrollLength);
}, scroll);
}
for (let i = 0; i < duration; i++) {
await page.screenshot({ path: workDir + i + ".png" });
await scrollPage();
}
await browser.close();
/* Creates array of pngs by listing files inside export folder then
removing extention, sort numerical strings in ascending order, and
finally adding path and extention to the file. */
let listOfPNGs = fs.readdirSync(workDir)
.map(a => a.substr(0, a.length - 4) + '')
.sort(function (a, b) { return a - b })
.map(a => workDir + a.substr(0, a.length) + '.png');
addToGif(listOfPNGs);
})();