Skip to content

Commit 4acc8a0

Browse files
author
Murali Govardhana
committed
Capture puppeteer video
1 parent 91df4d0 commit 4acc8a0

7 files changed

+512
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

background.js

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/* global chrome, MediaRecorder, FileReader */
2+
3+
chrome.runtime.onConnect.addListener(port => {
4+
let recorder = null;
5+
let filename = null;
6+
port.onMessage.addListener(msg => {
7+
console.log(msg);
8+
switch (msg.type) {
9+
case 'SET_EXPORT_PATH':
10+
filename = msg.filename
11+
break
12+
case 'REC_STOP':
13+
port.recorderPlaying = false
14+
recorder.stop()
15+
break
16+
case 'REC_CLIENT_PLAY':
17+
const tab = port.sender.tab
18+
tab.url = msg.data.url
19+
chrome.desktopCapture.chooseDesktopMedia(['tab', 'audio'], streamId => {
20+
// Get the stream
21+
navigator.webkitGetUserMedia({
22+
audio: false,
23+
video: {
24+
mandatory: {
25+
chromeMediaSource: 'desktop',
26+
chromeMediaSourceId: streamId,
27+
minWidth: 1280,
28+
maxWidth: 1280,
29+
minHeight: 720,
30+
maxHeight: 720,
31+
minFrameRate: 60,
32+
}
33+
}
34+
}, stream => {
35+
var chunks=[];
36+
recorder = new MediaRecorder(stream, {
37+
videoBitsPerSecond: 2500000,
38+
ignoreMutedMedia: true,
39+
mimeType: 'video/webm'
40+
});
41+
recorder.ondataavailable = function (event) {
42+
if (event.data.size > 0) {
43+
chunks.push(event.data);
44+
}
45+
};
46+
47+
recorder.onstop = function () {
48+
var superBuffer = new Blob(chunks, {
49+
type: 'video/webm'
50+
});
51+
52+
var url = URL.createObjectURL(superBuffer);
53+
// var a = document.createElement('a');
54+
// document.body.appendChild(a);
55+
// a.style = 'display: none';
56+
// a.href = url;
57+
// a.download = 'test.webm';
58+
// a.click();
59+
60+
chrome.downloads.download({
61+
url: url,
62+
filename: filename
63+
}, ()=>{
64+
});
65+
chrome.downloads.onChanged.addListener(function(delta) {
66+
if (!delta.state ||(delta.state.current != 'complete')) {
67+
return;
68+
}
69+
port.postMessage({downloadComplete: true})
70+
});
71+
}
72+
73+
recorder.start();
74+
}, error => console.log('Unable to get user media', error))
75+
})
76+
break
77+
default:
78+
console.log('Unrecognized message', msg)
79+
}
80+
})
81+
})

content_script.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
window.onload = () => {
2+
if (window.recorderInjected) return
3+
Object.defineProperty(window, 'recorderInjected', { value: true, writable: false })
4+
5+
// Setup message passing
6+
const port = chrome.runtime.connect(chrome.runtime.id)
7+
port.onMessage.addListener(msg => window.postMessage(msg, '*'))
8+
window.addEventListener('message', event => {
9+
// Relay client messages
10+
if (event.source === window && event.data.type) {
11+
port.postMessage(event.data)
12+
}
13+
if(event.data.type === 'PLAYBACK_COMPLETE'){
14+
port.postMessage({ type: 'REC_STOP' }, '*')
15+
}
16+
if(event.data.downloadComplete){
17+
document.querySelector('html').classList.add('downloadComplete')
18+
}
19+
})
20+
21+
document.title = 'puppetcam'
22+
window.postMessage({ type: 'REC_CLIENT_PLAY', data: { url: window.location.origin } }, '*')
23+
}

export.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const puppeteer = require('puppeteer');
2+
const Xvfb = require('xvfb');
3+
var xvfb = new Xvfb({silent: true});
4+
var width = 1280;
5+
var height = 720;
6+
var options = {
7+
headless: false,
8+
args: [
9+
'--enable-usermedia-screen-capturing',
10+
'--allow-http-screen-capture',
11+
'--auto-select-desktop-capture-source=puppetcam',
12+
'--load-extension=' + __dirname,,
13+
'--disable-extensions-except=' + __dirname,
14+
'--disable-infobars',
15+
`--window-size=${width},${height}`,
16+
],
17+
}
18+
19+
async function main() {
20+
xvfb.startSync()
21+
var url = process.argv[2], exportname = process.argv[3]
22+
if(!url){ url = 'http://tobiasahlin.com/spinkit/' }
23+
if(!exportname){ exportname = 'spinner.webm' }
24+
const browser = await puppeteer.launch(options)
25+
const pages = await browser.pages()
26+
const page = pages[0]
27+
await page._client.send('Emulation.clearDeviceMetricsOverride')
28+
await page.goto(url, {waitUntil: 'networkidle2'})
29+
await page.setBypassCSP(true)
30+
31+
// Perform any actions that have to be captured in the exported video
32+
await page.waitFor(8000)
33+
34+
await page.evaluate(filename=>{
35+
window.postMessage({type: 'SET_EXPORT_PATH', filename: filename}, '*')
36+
window.postMessage({type: 'REC_STOP'}, '*')
37+
}, exportname)
38+
39+
// Wait for download of webm to complete
40+
await page.waitForSelector('html.downloadComplete', {timeout: 0})
41+
await browser.close()
42+
xvfb.stopSync()
43+
}
44+
45+
main()
46+

manifest.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "Video Capture Attempt #1",
3+
"version": "0.1.0",
4+
"manifest_version": 2,
5+
"background": {
6+
"scripts": ["background.js"]
7+
},
8+
"content_scripts": [{
9+
"matches": ["<all_urls>"],
10+
"js": ["content_script.js"],
11+
"run_at": "document_start"
12+
}],
13+
"permissions": [
14+
"desktopCapture",
15+
"<all_urls>",
16+
"downloads"
17+
]
18+
}

0 commit comments

Comments
 (0)