UNPKG

puppeteer-stream

Version:

An Extension for Puppeteer to retrieve audio and/or video streams of a page

257 lines 21.1 kB
"use strict"; 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 (!opts.extensionPath) { opts.extensionPath = path.join(__dirname, "..", "extension"); } addToArgs("--load-extension=", opts.extensionPath); addToArgs("--disable-extensions-except=", opts.extensionPath); addToArgs("--allowlisted-extension-id=", extensionId); addToArgs("--autoplay-policy=no-user-gesture-required"); addToArgs("--auto-accept-this-tab-capture"); 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); } 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); }, }); function onConnection(ws, req) { const url = new URL(`http://localhost:${port}${req.url}`); if (url.searchParams.get("index") != index.toString()) return; async function close() { var _a, _b; if (!stream.readableEnded && !stream.writableEnded) stream.end(); if (!extension.isClosed() && extension.browser().isConnected()) { // @ts-ignore extension.evaluate((index) => STOP_RECORDING(index), index); } if (ws.readyState != ws_1.default.CLOSED) { setTimeout(() => { // await pending messages to be sent and then close the socket if (ws.readyState != ws_1.default.CLOSED) ws.close(); }, (_b = (_a = opts.streamConfig) === null || _a === void 0 ? void 0 : _a.closeTimeout) !== null && _b !== void 0 ? _b : 5000); } (await exports.wss).off("connection", onConnection); } ws.on("message", (data) => { 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); 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHVwcGV0ZWVyU3RyZWFtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1B1cHBldGVlclN0cmVhbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG1EQUt3QjtBQUN4QiwyQ0FBNkI7QUFDN0IsbUNBQW1DO0FBQ25DLHlDQUFnRDtBQUdoRCxNQUFNLFdBQVcsR0FBRyxrQ0FBa0MsQ0FBQztBQUN2RCxJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7QUFRckIsSUFBSSxJQUFZLENBQUM7QUFFSixRQUFBLEdBQUcsR0FBRyxDQUFDLEtBQUssSUFBSSxFQUFFO0lBQzlCLEtBQUssSUFBSSxDQUFDLEdBQUcsS0FBSyxFQUFFLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDcEMsTUFBTSxFQUFFLEdBQUcsSUFBSSxvQkFBZSxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDNUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDO1lBQ2xDLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7Z0JBQ3ZCLEVBQUUsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBTSxFQUFFLEVBQUU7b0JBQ3pCLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7Z0JBQzVDLENBQUMsQ0FBQyxDQUFDO1lBQ0osQ0FBQyxDQUFDO1lBQ0YsSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtnQkFDdkIsRUFBRSxDQUFDLEVBQUUsQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFO29CQUN2QixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2YsQ0FBQyxDQUFDLENBQUM7WUFDSixDQUFDLENBQUM7U0FDRixDQUFDLENBQUM7UUFDSCxJQUFJLE9B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