puppeteer-stream
Version:
An Extension for Puppeteer to retrieve audio and/or video streams of a page
270 lines • 22.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStream = exports.getExtensionPage = exports.launch = exports.wss = void 0;
const puppeteer_core_1 = require("puppeteer-core");
const path = __importStar(require("path"));
const stream_1 = require("stream");
const ws_1 = __importStar(require("ws"));
const extensionId = "jjndjgheafjngoipoacpjgeicjeomjli";
let currentIndex = 0;
let port;
exports.wss = (async () => {
for (let i = 55200; i <= 65535; i++) {
const ws = new ws_1.WebSocketServer({ port: i });
const promise = await Promise.race([
new Promise((resolve) => {
ws.on("error", (e) => {
resolve(!e.message.includes("EADDRINUSE"));
});
}),
new Promise((resolve) => {
ws.on("listening", () => {
resolve(true);
});
}),
]);
if (promise) {
port = i;
return ws;
}
}
})();
async function launch(arg1, opts) {
var _a, _b;
//if puppeteer library is not passed as first argument, then first argument is options
// @ts-ignore
if (typeof arg1.launch != "function")
opts = arg1;
if (!opts)
opts = {};
if (!opts.args)
opts.args = [];
function addToArgs(arg, value) {
if (!value) {
if (opts.args.includes(arg))
return;
return opts.args.push(arg);
}
let found = false;
opts.args = opts.args.map((x) => {
if (x.includes(arg)) {
found = true;
return x + "," + value;
}
return x;
});
if (!found)
opts.args.push(arg + value);
}
if (!Array.isArray(opts.enableExtensions))
opts.enableExtensions = [];
opts.enableExtensions.push(path.join(__dirname, "..", "extension"));
opts.pipe = true;
addToArgs("--autoplay-policy=no-user-gesture-required");
addToArgs("--auto-accept-this-tab-capture");
addToArgs(`--allowlisted-extension-id=${extensionId}`);
if (((_a = opts.defaultViewport) === null || _a === void 0 ? void 0 : _a.width) && ((_b = opts.defaultViewport) === null || _b === void 0 ? void 0 : _b.height)) {
opts.args.push(`--window-size=${opts.defaultViewport.width},${opts.defaultViewport.height}`);
opts.args.push(`--ozone-override-screen-size=${opts.defaultViewport.width},${opts.defaultViewport.height}`);
}
// @ts-ignore
opts.headless = opts.headless === "new" ? "new" : false;
if (opts.headless) {
if (!opts.ignoreDefaultArgs)
opts.ignoreDefaultArgs = [];
if (Array.isArray(opts.ignoreDefaultArgs) && !opts.ignoreDefaultArgs.includes("--mute-audio"))
opts.ignoreDefaultArgs.push("--mute-audio");
if (!opts.args.includes("--headless=new"))
opts.args.push("--headless=new");
}
let browser;
// @ts-ignore
if (typeof arg1.launch == "function") {
// @ts-ignore
browser = await arg1.launch(opts);
}
else {
browser = await (0, puppeteer_core_1.launch)(opts);
}
// Delay to let Chrome load the extension
await new Promise((r) => setTimeout(r, opts.startDelay || 250));
if (opts.allowIncognito) {
const settings = await browser.newPage();
await settings.goto(`chrome://extensions/?id=${extensionId}`);
await settings.evaluate(() => {
document
.querySelector("extensions-manager")
.shadowRoot.querySelector("#viewManager > extensions-detail-view.active")
.shadowRoot.querySelector("div#container.page-container > div.page-content > div#options-section extensions-toggle-row#allow-incognito")
.shadowRoot.querySelector("label#label input")
.click();
});
await settings.close();
}
(await browser.newPage()).goto(`chrome-extension://${extensionId}/options.html#${port}`);
const old_browser_close = browser.close;
browser.close = async () => {
for (const page of await browser.pages()) {
if (!page.url().startsWith(`chrome-extension://${extensionId}/options.html`)) {
await page.close();
}
}
const extension = await getExtensionPage(browser);
await extension.evaluate(async () => {
return chrome.tabs.query({});
});
if (opts.closeDelay) {
await new Promise((r) => setTimeout(r, opts.closeDelay));
}
await old_browser_close.call(browser);
};
return browser;
}
exports.launch = launch;
async function getExtensionPage(browser) {
const extensionTarget = await browser.waitForTarget((target) => {
return target.type() === "page" && target.url().startsWith(`chrome-extension://${extensionId}/options.html`);
});
if (!extensionTarget)
throw new Error("cannot load extension");
const videoCaptureExtension = await extensionTarget.page();
if (!videoCaptureExtension)
throw new Error("cannot get page of extension");
return videoCaptureExtension;
}
exports.getExtensionPage = getExtensionPage;
let mutex = false;
let queue = [];
function lock() {
return new Promise((res) => {
if (!mutex) {
mutex = true;
return res(null);
}
queue.push(res);
});
}
function unlock() {
if (queue.length)
queue.shift()();
else
mutex = false;
}
async function getStream(page, opts) {
var _a;
if (!opts.audio && !opts.video)
throw new Error("At least audio or video must be true");
if (!opts.mimeType) {
if (opts.video)
opts.mimeType = "video/webm";
else if (opts.audio)
opts.mimeType = "audio/webm";
}
if (!opts.frameSize)
opts.frameSize = 20;
const retryPolicy = Object.assign({}, { each: 20, times: 3 }, opts.retry);
const extension = await getExtensionPage(page.browser());
const highWaterMarkMB = ((_a = opts.streamConfig) === null || _a === void 0 ? void 0 : _a.highWaterMarkMB) || 8;
const index = currentIndex++;
await lock();
await page.bringToFront();
const [tab] = await extension.evaluate(async (x) => {
// @ts-ignore
return chrome.tabs.query(x);
}, opts.tabQuery || {
active: true,
});
unlock();
if (!tab)
throw new Error("Cannot find tab, try providing your own tabQuery to getStream options");
const stream = new stream_1.Transform({
highWaterMark: 1024 * 1024 * highWaterMarkMB,
transform(chunk, encoding, callback) {
callback(null, chunk);
},
});
stream.stop = async () => {
if (!extension.isClosed() && extension.browser().isConnected()) {
// @ts-ignore
await extension.evaluate((index) => STOP_RECORDING(index), index).catch(() => { });
}
};
function onConnection(ws, req) {
const url = new URL(`http://localhost:${port}${req.url}`);
if (url.searchParams.get("index") != index.toString())
return;
async function close() {
if (!extension.isClosed() && extension.browser().isConnected()) {
// @ts-ignore
extension.evaluate((index) => STOP_RECORDING(index), index).catch(() => { });
}
if (ws.readyState === ws_1.default.CLOSED) {
if (!stream.destroyed && !stream.readableEnded && !stream.writableEnded) {
stream.end();
}
}
(await exports.wss).off("connection", onConnection);
}
ws.on("message", (data) => {
if (!stream.destroyed && !stream.writableEnded) {
stream.write(data);
}
});
ws.on("close", close);
page.on("close", close);
stream.on("close", close);
}
(await exports.wss).on("connection", onConnection);
await lock();
await page.bringToFront();
await assertExtensionLoaded(extension, retryPolicy);
// Invoke extension via keyboard command to grant activeTab (Ctrl/Command+Shift+Y)
const isMac = process.platform === 'darwin';
await page.keyboard.down(isMac ? 'Meta' : 'Control');
await page.keyboard.down('Shift');
await page.keyboard.press('KeyY');
await page.keyboard.up('Shift');
await page.keyboard.up(isMac ? 'Meta' : 'Control');
// Small delay to let Chrome register the invocation
await new Promise((r) => setTimeout(r, 100));
await extension.evaluate(
// @ts-ignore
(settings) => START_RECORDING(settings), Object.assign(Object.assign({}, opts), { index, tabId: tab.id }));
unlock();
return stream;
}
exports.getStream = getStream;
async function assertExtensionLoaded(ext, opt) {
const wait = (ms) => new Promise((res) => setTimeout(res, ms));
for (let currentTick = 0; currentTick < opt.times; currentTick++) {
// @ts-ignore
if (await ext.evaluate(() => typeof START_RECORDING === "function"))
return;
await wait(Math.pow(opt.each, currentTick));
}
throw new Error("Could not find START_RECORDING function in the browser context");
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHVwcGV0ZWVyU3RyZWFtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1B1cHBldGVlclN0cmVhbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG1EQUt3QjtBQUN4QiwyQ0FBNkI7QUFDN0IsbUNBQW1DO0FBQ25DLHlDQUFnRDtBQUdoRCxNQUFNLFdBQVcsR0FBRyxrQ0FBa0MsQ0FBQztBQUN2RCxJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7QUFVckIsSUFBSSxJQUFZLENBQUM7QUFFSixRQUFBLEdBQUcsR0FBRyxDQUFDLEtBQUssSUFBSSxFQUFFO0lBQzlCLEtBQUssSUFBSSxDQUFDLEdBQUcsS0FBSyxFQUFFLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDcEMsTUFBTSxFQUFFLEdBQUcsSUFBSSxvQkFBZSxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDNUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDO1lBQ2xDLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7Z0JBQ3ZCLEVBQUUsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBTSxFQUFFLEVBQUU7b0JBQ3pCLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7Z0JBQzVDLENBQUMsQ0FBQyxDQUFDO1lBQ0osQ0FBQyxDQUFDO1lBQ0YsSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtnQkFDdkIsRUFBRSxDQUFDLEVBQUUsQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFO29CQUN2QixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2YsQ0FBQyxDQUFDLENBQUM7WUFDSixDQUFDLENBQUM7U0FDRixDQUFDLENBQUM7UUFDSCxJQUFJLE9B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