muralikg / puppetcam Goto Github PK
View Code? Open in Web Editor NEWExport puppeteer tab as webm video
License: MIT License
Export puppeteer tab as webm video
License: MIT License
Hey! I just tried cloning your repo to try and run some basic Puppeteer commands to output as a video and after running npm install
I'm getting an error on node export.js http://localhost:9000 spinner.webm
$ node export.js http://localhost:9000 spinner.webm
(node:1425) UnhandledPromiseRejectionWarning: Error: Could not start Xvfb.
at Xvfb.startSync ({home directory}/puppetcam/node_modules/xvfb/index.js:84:17)
... rest of stack trace
(node:1425) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:1425) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Running on Mac OSX 10.13.4, Node 10.5.0, NPM 6.1.0
Any idea what this could be?
chromium won't run on WSL & Xvfb won't run on Windows; why is headless: false? wouldnt running on a server require headless: true?
Hey,
My use case is to record a url where a video conference meeting is happening for more than an hour. There could be >30 meetings happening concurrently.
There is a cron job which runs at 11AM daily, which fetches the scheduled meetings for today and spawns instances of export.js when the meeting starts.
Some recordings do happen successfully but most of them emits one of the following errors -
Error: Protocol error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed.
Error: Page crashed!
Error: Protocol error (Runtime.callFunctionOn): Target closed.
My guess was that the recording video chunks are kept in browser memory (in background.js) and then on stop they are written to disk, and if the video file is large the process runs out of memory, so I tried running node export.js script with --max-old-space-size=2048
but still the same errors. Does the puppeteer browser run out of memory? How to increase the limit for that? I saw the CPU usage of machine, it is well under limit.
Also this might not be the appropriate place to ask this, but I am desperate to get an answer.
Sometimes its recording video of this URL: http://www.bellygraph.com/
The original URL that I am trying to make video is: http://prezentar.net:81/player/50825
Doesn't give any exception either.
Any thoughts?
Do I need to show you my code?
Thanks in advance!
Does this support mp4 video files? I've changed the MIME type to video/mp4
along with the Blob type but it seems like the video never finishes downloading. Does MediaRecorder not support this MIME type?
I try to record a video with custom dimension 720x1280 or 1280x720.
I expected the output to have the same dimension with the original video but the recorded video add some black space on top and bottom and (width, height) are different then original dimension.
Tell us about your environment:
Puppeteer version: 2.1.1
Platform: docker ubuntu
Landscape example:
Dimension used in export.js and background.js (width: 1280, height: 720)
Original video:
Exported record video:
If you see the last frame from exported video are the real size from original video size.
Portrait example
Dimension used in export.js and background.js (width: 720, height: 1280)
Original video:
Exported record video:
Used code for bunny example, in second example just dimension are different.
export.js
const express = require ('express');
const puppeteer = require('puppeteer');
const Xvfb = require('xvfb');
var xvfb = new Xvfb({silent: false});
const chromeExtensionPath = `${__dirname}/chrome-extension`;
// export DISPLAY=:99 && /etc/init.d/xvfb start
async function main() {
const PARTIAL_CONTENT_STATUS = 206;
return new Promise(async (resolve, reject) => {
try {
let browser = await puppeteer.launch({
headless: false,
devtools: false,
executablePath: '/usr/bin/google-chrome',
ignoreDefaultArgs: ['--mute-audio'],
defaultViewport: {
width: 1280,
height: 720,
},
args: [
'--enable-usermedia-screen-capturing',
'--allow-http-screen-capture',
'--auto-select-desktop-capture-source=puppetcam',
'--load-extension=' + chromeExtensionPath,
'--disable-extensions-except=' + chromeExtensionPath,
'--disable-infobars',
'--no-sandbox',
'--hide-scrollbars',
'--window-size=1280,720',
],
});
const page = await browser.newPage();
page.setViewport({
width: 1280,
height: 720,
})
page.on('console', msg => console.log('PAGE LOG:', msg.text()));
page.on('error', (e) => {
reject(e);
browser.close().catch(console.error);
});
page.on('requestfailed', (req) => {
const response = req.response();
if (response && response.status() === PARTIAL_CONTENT_STATUS) {
console.log([
'Ignoring failed request for ',
req.url(),
' with status 206 Partial Content. Range: ',
response && response.headers()['content-range'],
].join(''));
} else {
console.error('requestfailed', req.url(), req.failure().errorText);
}
});
const response = await page.goto('http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', {waitUntil: 'networkidle2'})
await page.waitFor(17000)
xvfb.startSync()
await page.evaluate(filename=>{
window.postMessage({type: 'SET_EXPORT_PATH', filename: filename}, '*')
window.postMessage({type: 'REC_STOP'}, '*')
}, 'bunny.webm')
// Wait for download of webm to complete
await page.waitForSelector('html.downloadComplete', {timeout: 0})
xvfb.stopSync()
if (response.status() < 200 || response.status() >= 400) {
throw new Error(`Preview server response error: ${await response.text()}`);
}
browser.close().catch(console.error);
} catch (e) {
console.error(e);
throw e;
}
});
}
const app = express();
// cors
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
// healthCheck @TODO: make it better
app.get('/health', (req, res) => {
res.status(200).send({ code: 200, body: 'OK' });
});
app.listen(4000, () => {
console.log(`Started to listen on port 4000`);
});
app.get('/export', () => {
console.log('here');
main()
});
background.js:
/* global chrome, MediaRecorder, FileReader */
console.log(`Background script loading`);
let recorder = null;
let filename = null;
chrome.runtime.onConnect.addListener(port => {
port.onMessage.addListener(msg => {
console.log(msg);
switch (msg.type) {
case 'SET_EXPORT_PATH':
console.log(`set export path`);
filename = msg.filename;
break;
case 'REC_STOP':
console.log(`REC STOP`);
recorder.stop();
break;
case 'REC_CLIENT_PLAY':
if (recorder) {
return;
}
const tab = port.sender.tab;
tab.url = msg.data.url;
const size = {width: 1280, height: 720};
chrome.desktopCapture.chooseDesktopMedia(['tab', 'audio'], streamId => {
// Get the stream
navigator.webkitGetUserMedia(
{
audio: {
mandatory: {
chromeMediaSource: 'system'
}
},
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: streamId,
minWidth: size.width,
maxWidth: size.width,
minHeight: size.height,
maxHeight: size.height,
minFrameRate: 60,
},
},
},
stream => {
var chunks = [];
recorder = new MediaRecorder(stream, {
videoBitsPerSecond: 2500000,
ignoreMutedMedia: true,
mimeType: 'video/webm',
});
recorder.ondataavailable = function(event) {
if (event.data.size > 0) {
chunks.push(event.data);
}
};
recorder.onstop = function() {
var superBuffer = new Blob(chunks, {
type: 'video/webm',
});
var url = URL.createObjectURL(superBuffer);
// var a = document.createElement('a');
// document.body.appendChild(a);
// a.style = 'display: none';
// a.href = url;
// a.download = 'test.webm';
// a.click();
chrome.downloads.download(
{
url: url,
filename: filename,
},
() => {
console.log(arguments);
},
);
};
recorder.start();
},
error => console.log('Unable to get user media', error),
);
});
break;
default:
console.log('Unrecognized message', msg);
}
});
chrome.downloads.onChanged.addListener(function(delta) {
if (!delta.state || delta.state.current != 'complete') {
return;
}
try {
port.postMessage({downloadComplete: true});
} catch (e) {}
});
});
Dockerfile:
FROM ubuntu
ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Europe/Bucharest
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update
RUN apt-get install -y curl xvfb x11vnc x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps nodejs npm tightvncserver xfce4 xfce4-goodies apt-utils gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget x11vnc x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps xvfb apt-utils openvpn fping nano libgtk-3.0 libatk-bridge2.0-0
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get purge --auto-remove -y curl \
&& rm -rf /src/*.deb
## Sound options for RHEL7 OpenClient
RUN snd_opts="--device /dev/snd \
-e PULSE_SERVER=unix:${XDG_RUNTIME_DIR}/pulse/native \
-v ${XDG_RUNTIME_DIR}/pulse/native:${XDG_RUNTIME_DIR}/pulse/native \
--group-add $(getent group audio | cut -d: -f3)"
RUN groupmod -g 92 audio
ADD xvfb_init /etc/init.d/xvfb
RUN chmod a+x /etc/init.d/xvfb
ADD xvfb_daemon_run /usr/bin/xvfb-daemon-run
RUN chmod a+x /usr/bin/xvfb-daemon-run
WORKDIR /cac
ADD package.json .
RUN npm install
COPY ./app ./app
ENV DISPLAY :99
I would like to be able to send the record screen event only after I've done a number of actions within my export.js file.
How would I go about this?
I'm currently working through the docs to try and find this as well, but have you seen any way to change the download location? Ideally I'd like to just download the video into a subdirectory relative to where the script is being run from, ie -
/puppetcam
export.js
... etc
/videos
spinner.webm <- can we get it here?
Currently it gets dropped into the ~/Downloads/spinner.webm
folder on my virtual machine, then I have to manually move to a linked folder to access (using Vagrant and Virtualbox with a *nix image)
I tried with a relative path as a filename, but no luck, still dropped it in ~/Downloads
Hi,
I am unable to see console.log output which are specified in background.js.
For example, I should be able to see output for line #8 console.log(msg);
. However, I don't see that when I execute the script using node export.js some_url some_file.webm
.
Any idea?
Thanks for putting this working example together, it works great as-is 👍 I just had a question while trying to add more steps to be recorded - it seems like the saved video will only have a few (if even more than one) frame saved.
Here's your main()
function with my few extra lines for testing
async function main() {
xvfb.startSync()
var url = process.argv[2], exportname = process.argv[3]
if(!url){ url = 'http://tobiasahlin.com/spinkit/' }
if(!exportname){ exportname = 'spinner.webm' }
const browser = await puppeteer.launch(options)
const pages = await browser.pages()
const page = pages[0]
await page._client.send('Emulation.clearDeviceMetricsOverride')
await page.goto(url, {waitUntil: 'networkidle2'})
await page.setBypassCSP(true)
// Perform any actions that have to be captured in the exported video
await page.waitFor(8000)
// Added steps
await page.goto('https://google.com', {waitUntil: 'networkidle2'})
await page.type('#tsf [name="q"]', 'sample search query');
let navigationPromise = page.waitForNavigation();
await page.click('#tsf [type=submit]');
await navigationPromise;
await page.waitFor(5000)
// -----
await page.evaluate(filename=>{
window.postMessage({type: 'SET_EXPORT_PATH', filename: filename}, '*')
window.postMessage({type: 'REC_STOP'}, '*')
}, exportname)
// Wait for download of webm to complete
await page.waitForSelector('html.downloadComplete', {timeout: 30000})
await browser.close()
xvfb.stopSync()
}
And here is the single frame spinner.webm that was saved
Any idea what's going on?
First of all amazing work!
I wanted to convert your code to an API. So users will provide me a URL and time and I will record that web page for specified time and will give the video to users. I just want to confirm that multiple requests will work fine? it would be creating new tabs and record video separately every time a user sends a request?
I know its a silly question but just wanted to confirm. :p
Regards,
Junaid
OS: ubuntu 14.04
Node: v8.11.3
fail log:
(node:10399) UnhandledPromiseRejectionWarning: Error: Could not start Xvfb.
at Xvfb.startSync (/home/test/puppetcam/node_modules/xvfb/index.js:84:17)
at main (/home/test/puppetcam/export.js:20:10)
at Object.<anonymous> (/home/test/puppetcam/export.js:45:1)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10)
at startup (bootstrap_node.js:191:16)
(node:10399) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:10399) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Trying to get 4k output, just added executablePath but in the output video it's showing the black border at the top and bottom of the video, check this screenshot below.
Using Node v12.18.0, and [email protected]
also I noticed this bar not sure if this is the problem
Here's the modified code, else everything is same.
const puppeteer = require("puppeteer-core");
let width = 3840;
let height = 2160;
let options = {
headless: false,
executablePath:
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\Chrome.exe",
args: [
"--enable-usermedia-screen-capturing",
"--allow-http-screen-capture",
"--auto-select-desktop-capture-source=puppetcam",
"--load-extension=" + __dirname,
"--disable-extensions-except=" + __dirname,
"--disable-infobars",
`--window-size=${width},${height}`,
],
};
Changing the mimeType:
recorder = new MediaRecorder(stream, {
videoBitsPerSecond: 2500000,
ignoreMutedMedia: true,
mimeType: 'video/webm;codecs=h264'
});
Still produces a VP8 encoded file. How do you recommend we support h.264?
Is this possible to do in a headless Ubuntu server considering google Authentication?
Does Puppetcam only save files in .webm format? Can I use .mp4 instead?
Any thoughts on how to accomplish this?
Tried to install on Ubuntu 18.04 headless server
$ npm install
> [email protected] install /home/ubuntu/puppetcam/node_modules/sleep
> node-gyp rebuild
make: Entering directory '/home/ubuntu/puppetcam/node_modules/sleep/build'
CXX(target) Release/obj.target/node_sleep/sleep.o
In file included from ../../nan/nan_converters.h:67:0,
from ../../nan/nan.h:202,
from ../sleep.cc:2:
../../nan/nan_converters_43_inl.h: In static member function ‘static Nan::imp::ToFactoryBase<v8::Boolean>::return_t Nan::imp::ToFactory<v8::Boolean>::convert(v8::Local<v8::Value>)’:
../../nan/nan_converters_43_inl.h:18:51: error: no matching function for call to ‘v8::Value::ToBoolean(v8::Local<v8::Context>)’
val->To ## TYPE(isolate->GetCurrentContext()) \
^
../../nan/nan_converters_43_inl.h:22:1: note: in expansion of macro ‘X’
X(Boolean)
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2845:18: note: candidate: v8::Local<v8::Boolean> v8::Value::ToBoolean(v8::Isolate*) const
Local<Boolean> ToBoolean(Isolate* isolate) const;
^~~~~~~~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2845:18: note: no known conversion for argument 1 from ‘v8::Local<v8::Context>’ to ‘v8::Isolate*’
In file included from ../../nan/nan_converters.h:67:0,
from ../../nan/nan.h:202,
from ../sleep.cc:2:
../../nan/nan_converters_43_inl.h: In static member function ‘static Nan::imp::ValueFactoryBase<bool>::return_t Nan::imp::ToFactory<bool>::convert(v8::Local<v8::Value>)’:
../../nan/nan_converters_43_inl.h:37:57: error: no matching function for call to ‘v8::Value::BooleanValue(v8::Local<v8::Context>)’
return val->NAME ## Value(isolate->GetCurrentContext()); \
^
../../nan/nan_converters_43_inl.h:40:1: note: in expansion of macro ‘X’
X(bool, Boolean)
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2855:8: note: candidate: bool v8::Value::BooleanValue(v8::Isolate*) const
bool BooleanValue(Isolate* isolate) const;
^~~~~~~~~~~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2855:8: note: no known conversion for argument 1 from ‘v8::Local<v8::Context>’ to ‘v8::Isolate*’
In file included from ../../nan/nan_new.h:189:0,
from ../../nan/nan.h:203,
from ../sleep.cc:2:
../../nan/nan_implementation_12_inl.h: In static member function ‘static Nan::imp::FactoryBase<v8::Function>::return_t Nan::imp::Factory<v8::Function>::New(Nan::FunctionCallback, v8::Local<v8::Value>)’:
../../nan/nan_implementation_12_inl.h:105:32: error: no matching function for call to ‘v8::Function::New(v8::Isolate*&, void (&)(const v8::FunctionCallbackInfo<v8::Value>&), v8::Local<v8::Object>&)’
, obj));
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:4407:31: note: candidate: static v8::MaybeLocal<v8::Function> v8::Function::New(v8::Local<v8::Context>, v8::FunctionCallback, v8::Local<v8::Value>, int, v8::ConstructorBehavior, v8::SideEffectType)
static MaybeLocal<Function> New(
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:4407:31: note: no known conversion for argument 1 from ‘v8::Isolate*’ to ‘v8::Local<v8::Context>’
In file included from ../../nan/nan_new.h:189:0,
from ../../nan/nan.h:203,
from ../sleep.cc:2:
../../nan/nan_implementation_12_inl.h: In static member function ‘static Nan::imp::FactoryBase<v8::StringObject>::return_t Nan::imp::Factory<v8::StringObject>::New(v8::Local<v8::String>)’:
../../nan/nan_implementation_12_inl.h:337:37: error: no matching function for call to ‘v8::StringObject::New(v8::Local<v8::String>&)’
return v8::StringObject::New(value).As<v8::StringObject>();
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:5784:23: note: candidate: static v8::Local<v8::Value> v8::StringObject::New(v8::Isolate*, v8::Local<v8::String>)
static Local<Value> New(Isolate* isolate, Local<String> value);
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:5784:23: note: candidate expects 2 arguments, 1 provided
In file included from ../../nan/nan_new.h:189:0,
from ../../nan/nan.h:203,
from ../sleep.cc:2:
../../nan/nan_implementation_12_inl.h:337:58: error: expected primary-expression before ‘>’ token
return v8::StringObject::New(value).As<v8::StringObject>();
^
../../nan/nan_implementation_12_inl.h:337:60: error: expected primary-expression before ‘)’ token
return v8::StringObject::New(value).As<v8::StringObject>();
^
In file included from ../sleep.cc:2:0:
../../nan/nan.h: In constructor ‘Nan::Utf8String::Utf8String(v8::Local<v8::Value>)’:
../../nan/nan.h:1034:53: error: no matching function for call to ‘v8::Value::ToString()’
v8::Local<v8::String> string = from->ToString();
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2807:44: note: candidate: v8::MaybeLocal<v8::String> v8::Value::ToString(v8::Local<v8::Context>) const
V8_WARN_UNUSED_RESULT MaybeLocal<String> ToString(
^~~~~~~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2807:44: note: candidate expects 1 argument, 0 provided
In file included from ../sleep.cc:2:0:
../../nan/nan.h:1044:74: error: no matching function for call to ‘v8::String::WriteUtf8(char*&, int, int, const int&)’
length_ = string->WriteUtf8(str_, static_cast<int>(len), 0, flags);
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3034:7: note: candidate: int v8::String::WriteUtf8(v8::Isolate*, char*, int, int*, int) const
int WriteUtf8(Isolate* isolate, char* buffer, int length = -1,
^~~~~~~~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3034:7: note: no known conversion for argument 1 from ‘char*’ to ‘v8::Isolate*’
In file included from ../sleep.cc:2:0:
../../nan/nan.h: In member function ‘void Nan::AsyncWorker::SaveToPersistent(const char*, const v8::Local<v8::Value>&)’:
../../nan/nan.h:1818:64: error: no matching function for call to ‘v8::Object::Set(v8::Local<v8::String>, const v8::Local<v8::Value>&)’
New(persistentHandle)->Set(New(key).ToLocalChecked(), value);
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3639:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, v8::Local<v8::Value>, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3639:37: note: candidate expects 3 arguments, 2 provided
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3642:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, uint32_t, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3642:37: note: candidate expects 3 arguments, 2 provided
In file included from ../sleep.cc:2:0:
../../nan/nan.h: In member function ‘void Nan::AsyncWorker::SaveToPersistent(const v8::Local<v8::String>&, const v8::Local<v8::Value>&)’:
../../nan/nan.h:1824:42: error: no matching function for call to ‘v8::Object::Set(const v8::Local<v8::String>&, const v8::Local<v8::Value>&)’
New(persistentHandle)->Set(key, value);
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3639:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, v8::Local<v8::Value>, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3639:37: note: candidate expects 3 arguments, 2 provided
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3642:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, uint32_t, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3642:37: note: candidate expects 3 arguments, 2 provided
In file included from ../sleep.cc:2:0:
../../nan/nan.h: In member function ‘void Nan::AsyncWorker::SaveToPersistent(uint32_t, const v8::Local<v8::Value>&)’:
../../nan/nan.h:1830:44: error: no matching function for call to ‘v8::Object::Set(uint32_t&, const v8::Local<v8::Value>&)’
New(persistentHandle)->Set(index, value);
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3639:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, v8::Local<v8::Value>, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3639:37: note: candidate expects 3 arguments, 2 provided
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3642:37: note: candidate: v8::Maybe<bool> v8::Object::Set(v8::Local<v8::Context>, uint32_t, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3642:37: note: candidate expects 3 arguments, 2 provided
In file included from ../sleep.cc:2:0:
../../nan/nan.h: In member function ‘v8::Local<v8::Value> Nan::AsyncWorker::GetFromPersistent(const char*) const’:
../../nan/nan.h:1836:61: error: no matching function for call to ‘v8::Object::Get(v8::Local<v8::String>)’
New(persistentHandle)->Get(New(key).ToLocalChecked()));
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3686:43: note: candidate: v8::MaybeLocal<v8::Value> v8::Object::Get(v8::Local<v8::Context>, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3686:43: note: candidate expects 2 arguments, 1 provided
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3689:43: note: candidate: v8::MaybeLocal<v8::Value> v8::Object::Get(v8::Local<v8::Context>, uint32_t)
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3689:43: note: candidate expects 2 arguments, 1 provided
In file included from ../sleep.cc:2:0:
../../nan/nan.h: In member function ‘v8::Local<v8::Value> Nan::AsyncWorker::GetFromPersistent(const v8::Local<v8::String>&) const’:
../../nan/nan.h:1842:55: error: no matching function for call to ‘v8::Object::Get(const v8::Local<v8::String>&)’
return scope.Escape(New(persistentHandle)->Get(key));
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3686:43: note: candidate: v8::MaybeLocal<v8::Value> v8::Object::Get(v8::Local<v8::Context>, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3686:43: note: candidate expects 2 arguments, 1 provided
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3689:43: note: candidate: v8::MaybeLocal<v8::Value> v8::Object::Get(v8::Local<v8::Context>, uint32_t)
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3689:43: note: candidate expects 2 arguments, 1 provided
In file included from ../sleep.cc:2:0:
../../nan/nan.h: In member function ‘v8::Local<v8::Value> Nan::AsyncWorker::GetFromPersistent(uint32_t) const’:
../../nan/nan.h:1847:57: error: no matching function for call to ‘v8::Object::Get(uint32_t&)’
return scope.Escape(New(persistentHandle)->Get(index));
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3686:43: note: candidate: v8::MaybeLocal<v8::Value> v8::Object::Get(v8::Local<v8::Context>, v8::Local<v8::Value>)
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3686:43: note: candidate expects 2 arguments, 1 provided
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3689:43: note: candidate: v8::MaybeLocal<v8::Value> v8::Object::Get(v8::Local<v8::Context>, uint32_t)
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
^~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:3689:43: note: candidate expects 2 arguments, 1 provided
In file included from /usr/include/c++/7/cassert:44:0,
from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node_object_wrap.h:26,
from ../../nan/nan.h:53,
from ../sleep.cc:2:
../../nan/nan_object_wrap.h: In destructor ‘virtual Nan::ObjectWrap::~ObjectWrap()’:
../../nan/nan_object_wrap.h:24:25: error: ‘class Nan::Persistent<v8::Object>’ has no member named ‘IsNearDeath’
assert(persistent().IsNearDeath());
^
In file included from ../../nan/nan.h:2657:0,
from ../sleep.cc:2:
../../nan/nan_object_wrap.h: In member function ‘void Nan::ObjectWrap::MakeWeak()’:
../../nan/nan_object_wrap.h:67:18: error: ‘class Nan::Persistent<v8::Object>’ has no member named ‘MarkIndependent’
persistent().MarkIndependent();
^~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/cassert:44:0,
from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node_object_wrap.h:26,
from ../../nan/nan.h:53,
from ../sleep.cc:2:
../../nan/nan_object_wrap.h: In static member function ‘static void Nan::ObjectWrap::WeakCallback(const v8::WeakCallbackInfo<Nan::ObjectWrap>&)’:
../../nan/nan_object_wrap.h:124:26: error: ‘class Nan::Persistent<v8::Object>’ has no member named ‘IsNearDeath’
assert(wrap->handle_.IsNearDeath());
^
../sleep.cc: At global scope:
../sleep.cc:6:11: error: ‘v8::Handle’ has not been declared
using v8::Handle;
^~~~~~
../sleep.cc: In function ‘Nan::NAN_METHOD_RETURN_TYPE Sleep(Nan::NAN_METHOD_ARGS_TYPE)’:
../sleep.cc:42:30: error: no matching function for call to ‘v8::Value::Uint32Value()’
sleep(info[0]->Uint32Value());
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2863:41: note: candidate: v8::Maybe<unsigned int> v8::Value::Uint32Value(v8::Local<v8::Context>) const
V8_WARN_UNUSED_RESULT Maybe<uint32_t> Uint32Value(
^~~~~~~~~~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2863:41: note: candidate expects 1 argument, 0 provided
../sleep.cc: In function ‘Nan::NAN_METHOD_RETURN_TYPE USleep(Nan::NAN_METHOD_ARGS_TYPE)’:
../sleep.cc:54:31: error: no matching function for call to ‘v8::Value::Uint32Value()’
usleep(info[0]->Uint32Value());
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2863:41: note: candidate: v8::Maybe<unsigned int> v8::Value::Uint32Value(v8::Local<v8::Context>) const
V8_WARN_UNUSED_RESULT Maybe<uint32_t> Uint32Value(
^~~~~~~~~~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:2863:41: note: candidate expects 1 argument, 0 provided
../sleep.cc: In function ‘void init(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE)’:
../sleep.cc:62:52: error: no matching function for call to ‘v8::FunctionTemplate::GetFunction()’
Nan::New<FunctionTemplate>(Sleep)->GetFunction());
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:6404:46: note: candidate: v8::MaybeLocal<v8::Function> v8::FunctionTemplate::GetFunction(v8::Local<v8::Context>)
V8_WARN_UNUSED_RESULT MaybeLocal<Function> GetFunction(
^~~~~~~~~~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:6404:46: note: candidate expects 1 argument, 0 provided
../sleep.cc:64:53: error: no matching function for call to ‘v8::FunctionTemplate::GetFunction()’
Nan::New<FunctionTemplate>(USleep)->GetFunction());
^
In file included from /home/ubuntu/.cache/node-gyp/14.3.0/include/node/node.h:67:0,
from ../../nan/nan.h:51,
from ../sleep.cc:2:
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:6404:46: note: candidate: v8::MaybeLocal<v8::Function> v8::FunctionTemplate::GetFunction(v8::Local<v8::Context>)
V8_WARN_UNUSED_RESULT MaybeLocal<Function> GetFunction(
^~~~~~~~~~~
/home/ubuntu/.cache/node-gyp/14.3.0/include/node/v8.h:6404:46: note: candidate expects 1 argument, 0 provided
node_sleep.target.mk:111: recipe for target 'Release/obj.target/node_sleep/sleep.o' failed
make: *** [Release/obj.target/node_sleep/sleep.o] Error 1
make: Leaving directory '/home/ubuntu/puppetcam/node_modules/sleep/build'
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
gyp ERR! stack at ChildProcess.emit (events.js:315:20)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:276:12)
gyp ERR! System Linux 5.0.0-1014-oracle
gyp ERR! command "/usr/bin/node" "/usr/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/ubuntu/puppetcam/node_modules/sleep
gyp ERR! node -v v14.3.0
gyp ERR! node-gyp -v v5.1.0
gyp ERR! not ok
> [email protected] install /home/ubuntu/puppetcam/node_modules/puppeteer
> node install.js
Downloading Chromium r571375 - 101.4 Mb [====================] 100% 0.0s
Chromium downloaded to /home/ubuntu/puppetcam/node_modules/puppeteer/.local-chromium/linux-571375
npm WARN [email protected] No repository field.
npm WARN [email protected] No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/sleep):
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] install: `node-gyp rebuild`
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: Exit status 1
added 42 packages from 22 contributors and audited 44 packages in 60.713s
found 3 vulnerabilities (1 low, 2 high)
run `npm audit fix` to fix them, or `npm audit` for details
``
Wanted to thank you. It works great. Good job.
Hey there,
first of all thanks a lot for sharing this!
I could make it work running inside a Docker container running locally on Docker for Windows so yay! :)
I'm now running the same Docker image in a Azure Function App and for some reason the scripts hangs waiting for the download completed signal.
To be more specific:
The last signal I am getting from the background script is the first line of the navigator.webkitGetUserMedia
callback (I'm using postMessage to report back to the content script where I can then capture the console.logs via puppeteer).
After that I'm not getting any messages not even from a setInterval(()=> port.postMessage(...), 1000)
I'm runningin the background script
I'm digging more into this adding as much logging as possible and using all the debugging tools available so I hope to report back soon.
But maybe you have an idea what could be going on?
Thanks for putting this together.
I'm trying to record video w/ audio. Out of the box this doesn't seem to work (on Ubuntu)--is it something you've looked into?
Hi,
Your repo is amazing and works well in Mac, Is it possible to record higher quality videos like 1080p. Currently its recording 720p.
Thanks
I am using code to record html-css animation video. The output video is recorded with black border around. How to get rid of this border. I tried to change the height and width in export.js but not worked.
Attached zip with webm file and screenshot showing black border
recorded_video_with_black_border.zip
Can it work in linux or mac environment
Thanks
error log on MacOS
/Users/username/NodeJS/puppetcam/node_modules/xvfb/index.js:84
throw new Error('Could not start Xvfb.');
^
Error: Could not start Xvfb.
at Xvfb.startSync (/Users/username/NodeJS/puppetcam/node_modules/xvfb/index.js:84:17)
at main (/Users/username/NodeJS/puppetcam/export.js:20:10)
at Object.<anonymous> (/Users/username/NodeJS/puppetcam/export.js:45:1)
at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1147:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
I want to put it in the docker, but in headless mode, it won't work. Is there any good way?
Thanks for the great work.
It's really help me a lot, thanks.
Hello, How can I have a perfect recording of what happens in the tab including audio?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.