pupeteer-screen-recorder 0.0.1-security → 3.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pupeteer-screen-recorder might be problematic. Click here for more details.

@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const events_1 = require("events");
30
+ const os_1 = __importDefault(require("os"));
31
+ const path_1 = require("path");
32
+ const stream_1 = require("stream");
33
+ const fluent_ffmpeg_1 = __importStar(require("fluent-ffmpeg"));
34
+ const pageVideoStreamTypes_1 = require("./pageVideoStreamTypes");
35
+ /**
36
+ * @ignore
37
+ */
38
+ const SUPPORTED_FILE_FORMATS = [
39
+ pageVideoStreamTypes_1.SupportedFileFormats.MP4,
40
+ pageVideoStreamTypes_1.SupportedFileFormats.AVI,
41
+ pageVideoStreamTypes_1.SupportedFileFormats.MOV,
42
+ pageVideoStreamTypes_1.SupportedFileFormats.WEBM,
43
+ ];
44
+ /**
45
+ * @ignore
46
+ */
47
+ class PageVideoStreamWriter extends events_1.EventEmitter {
48
+ constructor(destinationSource, options) {
49
+ super();
50
+ this.screenLimit = 10;
51
+ this.screenCastFrames = [];
52
+ this.duration = '00:00:00:00';
53
+ this.frameGain = 0;
54
+ this.frameLoss = 0;
55
+ this.status = pageVideoStreamTypes_1.VIDEO_WRITE_STATUS.NOT_STARTED;
56
+ this.videoMediatorStream = new stream_1.PassThrough();
57
+ if (options) {
58
+ this.options = options;
59
+ }
60
+ const isWritable = this.isWritableStream(destinationSource);
61
+ this.configureFFmPegPath();
62
+ if (isWritable) {
63
+ this.configureVideoWritableStream(destinationSource);
64
+ }
65
+ else {
66
+ this.configureVideoFile(destinationSource);
67
+ }
68
+ }
69
+ get videoFrameSize() {
70
+ const { width, height } = this.options.videoFrame;
71
+ return width !== null && height !== null ? `${width}x${height}` : '100%';
72
+ }
73
+ get autopad() {
74
+ const autopad = this.options.autopad;
75
+ return !autopad
76
+ ? { activation: false }
77
+ : { activation: true, color: autopad.color };
78
+ }
79
+ getFfmpegPath() {
80
+ if (this.options.ffmpeg_Path) {
81
+ return this.options.ffmpeg_Path;
82
+ }
83
+ try {
84
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
85
+ const ffmpeg = require('@ffmpeg-installer/ffmpeg');
86
+ if (ffmpeg.path) {
87
+ return ffmpeg.path;
88
+ }
89
+ return null;
90
+ }
91
+ catch (e) {
92
+ return null;
93
+ }
94
+ }
95
+ getDestinationPathExtension(destinationFile) {
96
+ const fileExtension = (0, path_1.extname)(destinationFile);
97
+ return fileExtension.includes('.')
98
+ ? fileExtension.replace('.', '')
99
+ : fileExtension;
100
+ }
101
+ configureFFmPegPath() {
102
+ const ffmpegPath = this.getFfmpegPath();
103
+ if (!ffmpegPath) {
104
+ throw new Error('FFmpeg path is missing, \n Set the FFMPEG_PATH env variable');
105
+ }
106
+ (0, fluent_ffmpeg_1.setFfmpegPath)(ffmpegPath);
107
+ }
108
+ isWritableStream(destinationSource) {
109
+ if (destinationSource && typeof destinationSource !== 'string') {
110
+ if (!(destinationSource instanceof stream_1.Writable) ||
111
+ !('writable' in destinationSource) ||
112
+ !destinationSource.writable) {
113
+ throw new Error('Output should be a writable stream');
114
+ }
115
+ return true;
116
+ }
117
+ return false;
118
+ }
119
+ configureVideoFile(destinationPath) {
120
+ const fileExt = this.getDestinationPathExtension(destinationPath);
121
+ if (!SUPPORTED_FILE_FORMATS.includes(fileExt)) {
122
+ throw new Error('File format is not supported');
123
+ }
124
+ this.writerPromise = new Promise((resolve) => {
125
+ const outputStream = this.getDestinationStream();
126
+ outputStream
127
+ .on('error', (e) => {
128
+ this.handleWriteStreamError(e.message);
129
+ resolve(false);
130
+ })
131
+ .on('stderr', (e) => {
132
+ this.handleWriteStreamError(e);
133
+ resolve(false);
134
+ })
135
+ .on('end', () => resolve(true))
136
+ .save(destinationPath);
137
+ if (fileExt == pageVideoStreamTypes_1.SupportedFileFormats.WEBM) {
138
+ outputStream
139
+ .videoCodec('libvpx')
140
+ .videoBitrate(this.options.videoBitrate || 1000, true)
141
+ .outputOptions('-flags', '+global_header', '-psnr');
142
+ }
143
+ });
144
+ }
145
+ configureVideoWritableStream(writableStream) {
146
+ this.writerPromise = new Promise((resolve) => {
147
+ const outputStream = this.getDestinationStream();
148
+ outputStream
149
+ .on('error', (e) => {
150
+ writableStream.emit('error', e);
151
+ resolve(false);
152
+ })
153
+ .on('stderr', (e) => {
154
+ writableStream.emit('error', { message: e });
155
+ resolve(false);
156
+ })
157
+ .on('end', () => {
158
+ writableStream.end();
159
+ resolve(true);
160
+ });
161
+ outputStream.toFormat('mp4');
162
+ outputStream.addOutputOptions('-movflags +frag_keyframe+separate_moof+omit_tfhd_offset+empty_moov');
163
+ outputStream.pipe(writableStream);
164
+ });
165
+ }
166
+ getOutputOption() {
167
+ var _a, _b;
168
+ const cpu = Math.max(1, os_1.default.cpus().length - 1);
169
+ const videoOutputOptions = (_a = this.options.videOutputOptions) !== null && _a !== void 0 ? _a : [];
170
+ const outputOptions = [];
171
+ outputOptions.push(`-crf ${(_b = this.options.videoCrf) !== null && _b !== void 0 ? _b : 23}`);
172
+ outputOptions.push(`-preset ${this.options.videoPreset || 'ultrafast'}`);
173
+ outputOptions.push(`-pix_fmt ${this.options.videoPixelFormat || 'yuv420p'}`);
174
+ outputOptions.push(`-minrate ${this.options.videoBitrate || 1000}`);
175
+ outputOptions.push(`-maxrate ${this.options.videoBitrate || 1000}`);
176
+ outputOptions.push('-framerate 1');
177
+ outputOptions.push(`-threads ${cpu}`);
178
+ outputOptions.push(`-loglevel error`);
179
+ videoOutputOptions.forEach((options) => {
180
+ outputOptions.push(options);
181
+ });
182
+ return outputOptions;
183
+ }
184
+ addVideoMetadata(outputStream) {
185
+ var _a;
186
+ const metadataOptions = (_a = this.options.metadata) !== null && _a !== void 0 ? _a : [];
187
+ for (const metadata of metadataOptions) {
188
+ outputStream.outputOptions('-metadata', metadata);
189
+ }
190
+ }
191
+ getDestinationStream() {
192
+ var _a;
193
+ const outputStream = (0, fluent_ffmpeg_1.default)({
194
+ source: this.videoMediatorStream,
195
+ priority: 20,
196
+ })
197
+ .videoCodec(this.options.videoCodec || 'libx264')
198
+ .size(this.videoFrameSize)
199
+ .aspect(this.options.aspectRatio || '4:3')
200
+ .autopad(this.autopad.activation, (_a = this.autopad) === null || _a === void 0 ? void 0 : _a.color)
201
+ .inputFormat('image2pipe')
202
+ .inputFPS(this.options.fps)
203
+ .outputOptions(this.getOutputOption())
204
+ .on('progress', (progressDetails) => {
205
+ this.duration = progressDetails.timemark;
206
+ });
207
+ this.addVideoMetadata(outputStream);
208
+ if (this.options.recordDurationLimit) {
209
+ outputStream.duration(this.options.recordDurationLimit);
210
+ }
211
+ return outputStream;
212
+ }
213
+ handleWriteStreamError(errorMessage) {
214
+ this.emit('videoStreamWriterError', errorMessage);
215
+ if (this.status !== pageVideoStreamTypes_1.VIDEO_WRITE_STATUS.IN_PROGRESS &&
216
+ errorMessage.includes('pipe:0: End of file')) {
217
+ return;
218
+ }
219
+ return console.error(`Error unable to capture video stream: ${errorMessage}`);
220
+ }
221
+ findSlot(timestamp) {
222
+ if (this.screenCastFrames.length === 0) {
223
+ return 0;
224
+ }
225
+ let i;
226
+ let frame;
227
+ for (i = this.screenCastFrames.length - 1; i >= 0; i--) {
228
+ frame = this.screenCastFrames[i];
229
+ if (timestamp > frame.timestamp) {
230
+ break;
231
+ }
232
+ }
233
+ return i + 1;
234
+ }
235
+ insert(frame) {
236
+ // reduce the queue into half when it is full
237
+ if (this.screenCastFrames.length === this.screenLimit) {
238
+ const numberOfFramesToSplice = Math.floor(this.screenLimit / 2);
239
+ const framesToProcess = this.screenCastFrames.splice(0, numberOfFramesToSplice);
240
+ this.processFrameBeforeWrite(framesToProcess, this.screenCastFrames[0].timestamp);
241
+ }
242
+ const insertionIndex = this.findSlot(frame.timestamp);
243
+ if (insertionIndex === this.screenCastFrames.length) {
244
+ this.screenCastFrames.push(frame);
245
+ }
246
+ else {
247
+ this.screenCastFrames.splice(insertionIndex, 0, frame);
248
+ }
249
+ }
250
+ trimFrame(fameList, chunckEndTime) {
251
+ return fameList.map((currentFrame, index) => {
252
+ const endTime = index !== fameList.length - 1
253
+ ? fameList[index + 1].timestamp
254
+ : chunckEndTime;
255
+ const duration = endTime - currentFrame.timestamp;
256
+ return Object.assign(Object.assign({}, currentFrame), { duration });
257
+ });
258
+ }
259
+ processFrameBeforeWrite(frames, chunckEndTime) {
260
+ const processedFrames = this.trimFrame(frames, chunckEndTime);
261
+ processedFrames.forEach(({ blob, duration }) => {
262
+ this.write(blob, duration);
263
+ });
264
+ }
265
+ write(data, durationSeconds = 1) {
266
+ this.status = pageVideoStreamTypes_1.VIDEO_WRITE_STATUS.IN_PROGRESS;
267
+ const totalFrames = durationSeconds * this.options.fps;
268
+ const floored = Math.floor(totalFrames);
269
+ let numberOfFPS = Math.max(floored, 1);
270
+ if (floored === 0) {
271
+ this.frameGain += 1 - totalFrames;
272
+ }
273
+ else {
274
+ this.frameLoss += totalFrames - floored;
275
+ }
276
+ while (1 < this.frameLoss) {
277
+ this.frameLoss--;
278
+ numberOfFPS++;
279
+ }
280
+ while (1 < this.frameGain) {
281
+ this.frameGain--;
282
+ numberOfFPS--;
283
+ }
284
+ for (let i = 0; i < numberOfFPS; i++) {
285
+ this.videoMediatorStream.write(data);
286
+ }
287
+ }
288
+ drainFrames(stoppedTime) {
289
+ this.processFrameBeforeWrite(this.screenCastFrames, stoppedTime);
290
+ this.screenCastFrames = [];
291
+ }
292
+ stop(stoppedTime = Date.now() / 1000) {
293
+ if (this.status === pageVideoStreamTypes_1.VIDEO_WRITE_STATUS.COMPLETED) {
294
+ return this.writerPromise;
295
+ }
296
+ this.drainFrames(stoppedTime);
297
+ this.videoMediatorStream.end();
298
+ this.status = pageVideoStreamTypes_1.VIDEO_WRITE_STATUS.COMPLETED;
299
+ return this.writerPromise;
300
+ }
301
+ }
302
+ exports.default = PageVideoStreamWriter;
303
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnZVZpZGVvU3RyZWFtV3JpdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9wYWdlVmlkZW9TdHJlYW1Xcml0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG1DQUFzQztBQUN0Qyw0Q0FBb0I7QUFDcEIsK0JBQStCO0FBQy9CLG1DQUErQztBQUUvQywrREFBc0Q7QUFFdEQsaUVBS2dDO0FBRWhDOztHQUVHO0FBQ0gsTUFBTSxzQkFBc0IsR0FBRztJQUM3QiwyQ0FBb0IsQ0FBQyxHQUFHO0lBQ3hCLDJDQUFvQixDQUFDLEdBQUc7SUFDeEIsMkNBQW9CLENBQUMsR0FBRztJQUN4QiwyQ0FBb0IsQ0FBQyxJQUFJO0NBQzFCLENBQUM7QUFFRjs7R0FFRztBQUNILE1BQXFCLHFCQUFzQixTQUFRLHFCQUFZO0lBYTdELFlBQVksaUJBQW9DLEVBQUUsT0FBc0I7UUFDdEUsS0FBSyxFQUFFLENBQUM7UUFiTyxnQkFBVyxHQUFHLEVBQUUsQ0FBQztRQUMxQixxQkFBZ0IsR0FBRyxFQUFFLENBQUM7UUFDdkIsYUFBUSxHQUFHLGFBQWEsQ0FBQztRQUN6QixjQUFTLEdBQUcsQ0FBQyxDQUFDO1FBQ2QsY0FBUyxHQUFHLENBQUMsQ0FBQztRQUViLFdBQU0sR0FBRyx5Q0FBa0IsQ0FBQyxXQUFXLENBQUM7UUFHeEMsd0JBQW1CLEdBQWdCLElBQUksb0JBQVcsRUFBRSxDQUFDO1FBTTNELElBQUksT0FBTyxFQUFFO1lBQ1gsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7U0FDeEI7UUFFRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUM1RCxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUMzQixJQUFJLFVBQVUsRUFBRTtZQUNkLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxpQkFBNkIsQ0FBQyxDQUFD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
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ import puppeteer from 'puppeteer';
2
+ import { PuppeteerScreenRecorder } from '../lib/PuppeteerScreenRecorder';
3
+ /** @ignore */
4
+ function sleep(time) {
5
+ return new Promise((resolve) => {
6
+ setTimeout(resolve, time);
7
+ });
8
+ }
9
+ /** @ignore */
10
+ async function testStartMethod(format) {
11
+ const executablePath = process.env['PUPPETEER_EXECUTABLE_PATH'];
12
+ const browser = await puppeteer.launch({
13
+ ...(executablePath ? { executablePath: executablePath } : {}),
14
+ headless: false,
15
+ });
16
+ const page = await browser.newPage();
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ const recorder = new PuppeteerScreenRecorder(page);
19
+ await page.setViewport({
20
+ width: 1920,
21
+ height: 1080,
22
+ deviceScaleFactor: 1,
23
+ });
24
+ await recorder.start(format);
25
+ await page.goto('https://developer.mozilla.org/en-US/docs/Web/CSS/animation');
26
+ await sleep(10 * 1000);
27
+ await recorder.stop();
28
+ await browser.close();
29
+ }
30
+ async function executeSample(format) {
31
+ return testStartMethod(format);
32
+ }
33
+ executeSample('./report/video/simple1.mp4').then(() => {
34
+ console.log('completed');
35
+ });
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZXhhbXBsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFNBQVMsTUFBTSxXQUFXLENBQUM7QUFFbEMsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFFekUsY0FBYztBQUNkLFNBQVMsS0FBSyxDQUFDLElBQVk7SUFDekIsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO1FBQzdCLFVBQVUsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDNUIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsY0FBYztBQUNkLEtBQUssVUFBVSxlQUFlLENBQUMsTUFBYztJQUMzQyxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLDJCQUEyQixDQUFDLENBQUM7SUFDaEUsTUFBTSxPQUFPLEdBQUcsTUFBTSxTQUFTLENBQUMsTUFBTSxDQUFDO1FBQ3JDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLEVBQUUsY0FBYyxFQUFFLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDN0QsUUFBUSxFQUFFLEtBQUs7S0FDaEIsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxJQUFJLEdBQUcsTUFBTSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDckMsOERBQThEO0lBQzlELE1BQU0sUUFBUSxHQUFHLElBQUksdUJBQXVCLENBQUMsSUFBVyxDQUFDLENBQUM7SUFDMUQsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDO1FBQ3JCLEtBQUssRUFBRSxJQUFJO1FBQ1gsTUFBTSxFQUFFLElBQUk7UUFDWixpQkFBaUIsRUFBRSxDQUFDO0tBQ3JCLENBQUMsQ0FBQztJQUVILE1BQU0sUUFBUSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUU3QixNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsNERBQTRELENBQUMsQ0FBQztJQUM5RSxNQUFNLEtBQUssQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFFdkIsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDdEIsTUFBTSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7QUFDeEIsQ0FBQztBQUVELEtBQUssVUFBVSxhQUFhLENBQUMsTUFBTTtJQUNqQyxPQUFPLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUNqQyxDQUFDO0FBRUQsYUFBYSxDQUFDLDRCQUE0QixDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRTtJQUNwRCxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQzNCLENBQUMsQ0FBQyxDQUFDIn0=
@@ -0,0 +1,2 @@
1
+ export * from './lib/pageVideoStreamTypes';
2
+ export * from './lib/PuppeteerScreenRecorder';
@@ -0,0 +1,3 @@
1
+ export * from './lib/pageVideoStreamTypes';
2
+ export * from './lib/PuppeteerScreenRecorder';
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLCtCQUErQixDQUFDIn0=
@@ -0,0 +1,85 @@
1
+ /// <reference types="node" />
2
+ import { Writable } from 'stream';
3
+ import { Page } from 'puppeteer';
4
+ /**
5
+ * PuppeteerScreenRecorder class is responsible for managing the video
6
+ *
7
+ * ```typescript
8
+ * const screenRecorderOptions = {
9
+ * followNewTab: true,
10
+ * fps: 15,
11
+ * }
12
+ * const savePath = "./test/demo.mp4";
13
+ * const screenRecorder = new PuppeteerScreenRecorder(page, screenRecorderOptions);
14
+ * await screenRecorder.start(savePath);
15
+ * // some puppeteer action or test
16
+ * await screenRecorder.stop()
17
+ * ```
18
+ */
19
+ export declare class PuppeteerScreenRecorder {
20
+ private page;
21
+ private options;
22
+ private streamReader;
23
+ private streamWriter;
24
+ private isScreenCaptureEnded;
25
+ constructor(page: Page, options?: {});
26
+ /**
27
+ * @ignore
28
+ */
29
+ private setupListeners;
30
+ /**
31
+ * @ignore
32
+ */
33
+ private ensureDirectoryExist;
34
+ /**
35
+ * @ignore
36
+ * @private
37
+ * @method startStreamReader
38
+ * @description start listening for video stream from the page.
39
+ * @returns PuppeteerScreenRecorder
40
+ */
41
+ private startStreamReader;
42
+ /**
43
+ * @public
44
+ * @method getRecordDuration
45
+ * @description return the total duration of the video recorded,
46
+ * 1. if this method is called before calling the stop method, it would be return the time till it has recorded.
47
+ * 2. if this method is called after stop method, it would give the total time for recording
48
+ * @returns total duration of video
49
+ */
50
+ getRecordDuration(): string;
51
+ /**
52
+ *
53
+ * @public
54
+ * @method start
55
+ * @param savePath accepts a path string to store the video
56
+ * @description Start the video capturing session
57
+ * @returns PuppeteerScreenRecorder
58
+ * @example
59
+ * ```
60
+ * const savePath = './test/demo.mp4'; //.mp4 is required
61
+ * await recorder.start(savePath);
62
+ * ```
63
+ */
64
+ start(savePath: string): Promise<PuppeteerScreenRecorder>;
65
+ /**
66
+ *
67
+ * @public
68
+ * @method startStream
69
+ * @description Start the video capturing session in a stream
70
+ * @returns {PuppeteerScreenRecorder}
71
+ * @example
72
+ * ```
73
+ * const stream = new PassThrough();
74
+ * await recorder.startStream(stream);
75
+ * ```
76
+ */
77
+ startStream(stream: Writable): Promise<PuppeteerScreenRecorder>;
78
+ /**
79
+ * @public
80
+ * @method stop
81
+ * @description stop the video capturing session
82
+ * @returns indicate whether stop is completed correct or not, if true without any error else false.
83
+ */
84
+ stop(): Promise<boolean>;
85
+ }
@@ -0,0 +1,146 @@
1
+ import fs from 'fs';
2
+ import { dirname } from 'path';
3
+ import { pageVideoStreamCollector } from './pageVideoStreamCollector';
4
+ import PageVideoStreamWriter from './pageVideoStreamWriter';
5
+ /**
6
+ * @ignore
7
+ * @default
8
+ * @description This will be option passed to the puppeteer screen recorder
9
+ */
10
+ const defaultPuppeteerScreenRecorderOptions = {
11
+ followNewTab: true,
12
+ fps: 15,
13
+ quality: 100,
14
+ ffmpeg_Path: null,
15
+ videoFrame: {
16
+ width: null,
17
+ height: null,
18
+ },
19
+ aspectRatio: '4:3',
20
+ };
21
+ /**
22
+ * PuppeteerScreenRecorder class is responsible for managing the video
23
+ *
24
+ * ```typescript
25
+ * const screenRecorderOptions = {
26
+ * followNewTab: true,
27
+ * fps: 15,
28
+ * }
29
+ * const savePath = "./test/demo.mp4";
30
+ * const screenRecorder = new PuppeteerScreenRecorder(page, screenRecorderOptions);
31
+ * await screenRecorder.start(savePath);
32
+ * // some puppeteer action or test
33
+ * await screenRecorder.stop()
34
+ * ```
35
+ */
36
+ export class PuppeteerScreenRecorder {
37
+ page;
38
+ options;
39
+ streamReader;
40
+ streamWriter;
41
+ isScreenCaptureEnded = null;
42
+ constructor(page, options = {}) {
43
+ this.options = Object.assign({}, defaultPuppeteerScreenRecorderOptions, options);
44
+ this.streamReader = new pageVideoStreamCollector(page, this.options);
45
+ this.page = page;
46
+ }
47
+ /**
48
+ * @ignore
49
+ */
50
+ setupListeners() {
51
+ this.page.once('close', async () => await this.stop());
52
+ this.streamReader.on('pageScreenFrame', (pageScreenFrame) => {
53
+ this.streamWriter.insert(pageScreenFrame);
54
+ });
55
+ this.streamWriter.once('videoStreamWriterError', () => this.stop());
56
+ }
57
+ /**
58
+ * @ignore
59
+ */
60
+ async ensureDirectoryExist(dirPath) {
61
+ return new Promise((resolve, reject) => {
62
+ try {
63
+ fs.mkdirSync(dirPath, { recursive: true });
64
+ return resolve(dirPath);
65
+ }
66
+ catch (error) {
67
+ reject(error);
68
+ }
69
+ });
70
+ }
71
+ /**
72
+ * @ignore
73
+ * @private
74
+ * @method startStreamReader
75
+ * @description start listening for video stream from the page.
76
+ * @returns PuppeteerScreenRecorder
77
+ */
78
+ async startStreamReader() {
79
+ this.setupListeners();
80
+ await this.streamReader.start();
81
+ return this;
82
+ }
83
+ /**
84
+ * @public
85
+ * @method getRecordDuration
86
+ * @description return the total duration of the video recorded,
87
+ * 1. if this method is called before calling the stop method, it would be return the time till it has recorded.
88
+ * 2. if this method is called after stop method, it would give the total time for recording
89
+ * @returns total duration of video
90
+ */
91
+ getRecordDuration() {
92
+ if (!this.streamWriter) {
93
+ return '00:00:00:00';
94
+ }
95
+ return this.streamWriter.duration;
96
+ }
97
+ /**
98
+ *
99
+ * @public
100
+ * @method start
101
+ * @param savePath accepts a path string to store the video
102
+ * @description Start the video capturing session
103
+ * @returns PuppeteerScreenRecorder
104
+ * @example
105
+ * ```
106
+ * const savePath = './test/demo.mp4'; //.mp4 is required
107
+ * await recorder.start(savePath);
108
+ * ```
109
+ */
110
+ async start(savePath) {
111
+ await this.ensureDirectoryExist(dirname(savePath));
112
+ this.streamWriter = new PageVideoStreamWriter(savePath, this.options);
113
+ return this.startStreamReader();
114
+ }
115
+ /**
116
+ *
117
+ * @public
118
+ * @method startStream
119
+ * @description Start the video capturing session in a stream
120
+ * @returns {PuppeteerScreenRecorder}
121
+ * @example
122
+ * ```
123
+ * const stream = new PassThrough();
124
+ * await recorder.startStream(stream);
125
+ * ```
126
+ */
127
+ async startStream(stream) {
128
+ this.streamWriter = new PageVideoStreamWriter(stream, this.options);
129
+ return this.startStreamReader();
130
+ }
131
+ /**
132
+ * @public
133
+ * @method stop
134
+ * @description stop the video capturing session
135
+ * @returns indicate whether stop is completed correct or not, if true without any error else false.
136
+ */
137
+ async stop() {
138
+ if (this.isScreenCaptureEnded !== null) {
139
+ return this.isScreenCaptureEnded;
140
+ }
141
+ await this.streamReader.stop();
142
+ this.isScreenCaptureEnded = await this.streamWriter.stop();
143
+ return this.isScreenCaptureEnded;
144
+ }
145
+ }
146
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHVwcGV0ZWVyU2NyZWVuUmVjb3JkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL1B1cHBldGVlclNjcmVlblJlY29yZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQztBQUNwQixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBSy9CLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXRFLE9BQU8scUJBQXFCLE1BQU0seUJBQXlCLENBQUM7QUFFNUQ7Ozs7R0FJRztBQUNILE1BQU0scUNBQXFDLEdBQW1DO0lBQzVFLFlBQVksRUFBRSxJQUFJO0lBQ2xCLEdBQUcsRUFBRSxFQUFFO0lBQ1AsT0FBTyxFQUFFLEdBQUc7SUFDWixXQUFXLEVBQUUsSUFBSTtJQUNqQixVQUFVLEVBQUU7UUFDVixLQUFLLEVBQUUsSUFBSTtRQUNYLE1BQU0sRUFBRSxJQUFJO0tBQ2I7SUFDRCxXQUFXLEVBQUUsS0FBSztDQUNuQixDQUFDO0FBRUY7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLE9BQU8sdUJBQXVCO0lBQzFCLElBQUksQ0FBTztJQUNYLE9BQU8sQ0FBaUM7SUFDeEMsWUFBWSxDQUEyQjtJQUN2QyxZQUFZLENBQXdCO0lBQ3BDLG9CQUFvQixHQUFtQixJQUFJLENBQUM7SUFFcEQsWUFBWSxJQUFVLEVBQUUsT0FBTyxHQUFHLEVBQUU7UUFDbEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUMxQixFQUFFLEVBQ0YscUNBQXFDLEVBQ3JDLE9BQU8sQ0FDUixDQUFDO1FBQ0YsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLHdCQUF3QixDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDckUsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7SUFDbkIsQ0FBQztJQUVEOztP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
@@ -0,0 +1,28 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import { Page } from 'puppeteer';
4
+ import { PuppeteerScreenRecorderOptions } from './pageVideoStreamTypes';
5
+ /**
6
+ * @ignore
7
+ */
8
+ export declare class pageVideoStreamCollector extends EventEmitter {
9
+ private page;
10
+ private options;
11
+ private sessionsStack;
12
+ private isStreamingEnded;
13
+ private isFrameAckReceived;
14
+ constructor(page: Page, options: PuppeteerScreenRecorderOptions);
15
+ private get shouldFollowPopupWindow();
16
+ private getPageSession;
17
+ private getCurrentSession;
18
+ private addListenerOnTabOpens;
19
+ private removeListenerOnTabClose;
20
+ private registerTabListener;
21
+ private startScreenCast;
22
+ private stopScreenCast;
23
+ private startSession;
24
+ private handleScreenCastFrame;
25
+ private endSession;
26
+ start(): Promise<void>;
27
+ stop(): Promise<boolean>;
28
+ }