UNPKG

ghost-cursor-frames

Version:

Move your mouse like a human in puppeteer or generate realistic movements on any 2D plane, this version has support for iframes

505 lines (504 loc) 24.6 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createCursor = exports.path = exports.getRandomPagePoint = exports.installMouseHelper = void 0; var math_1 = require("./math"); var mouse_helper_1 = require("./mouse-helper"); Object.defineProperty(exports, "installMouseHelper", { enumerable: true, get: function () { return __importDefault(mouse_helper_1).default; } }); var delay = function (ms) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4, new Promise(function (resolve) { return setTimeout(resolve, ms); })]; case 1: return [2, _a.sent()]; } }); }); }; var fitts = function (distance, width) { var a = 0; var b = 2; var id = Math.log2(distance / width + 1); return a + b * id; }; var getRandomBoxPoint = function (_a, options) { var x = _a.x, y = _a.y, width = _a.width, height = _a.height; var paddingWidth = 0; var paddingHeight = 0; if ((options === null || options === void 0 ? void 0 : options.paddingPercentage) !== undefined && (options === null || options === void 0 ? void 0 : options.paddingPercentage) > 0 && (options === null || options === void 0 ? void 0 : options.paddingPercentage) < 100) { paddingWidth = width * options.paddingPercentage / 100; paddingHeight = height * options.paddingPercentage / 100; } return { x: x + (paddingWidth / 2) + Math.random() * (width - paddingWidth), y: y + (paddingHeight / 2) + Math.random() * (height - paddingHeight) }; }; var getRandomPagePoint = function (page) { return __awaiter(void 0, void 0, void 0, function () { var targetId, window; var _a, _b; return __generator(this, function (_c) { switch (_c.label) { case 0: targetId = page.target()._targetId; return [4, page._client.send('Browser.getWindowForTarget', { targetId: targetId })]; case 1: window = _c.sent(); return [2, getRandomBoxPoint({ x: math_1.origin.x, y: math_1.origin.y, width: (_a = window.bounds.width) !== null && _a !== void 0 ? _a : 0, height: (_b = window.bounds.height) !== null && _b !== void 0 ? _b : 0 })]; } }); }); }; exports.getRandomPagePoint = getRandomPagePoint; var getElementBox = function (page, element, relativeToMainFrame) { if (relativeToMainFrame === void 0) { relativeToMainFrame = true; } return __awaiter(void 0, void 0, void 0, function () { var quads, elementBox, elementFrame, iframes, _a, frame, iframes_1, iframes_1_1, iframe, e_1_1, boundingBox, _1; var e_1, _b; var _c; return __generator(this, function (_d) { switch (_d.label) { case 0: if (element._remoteObject.objectId === undefined) { return [2, null]; } _d.label = 1; case 1: _d.trys.push([1, 16, , 18]); return [4, page._client.send('DOM.getContentQuads', { objectId: element._remoteObject.objectId })]; case 2: quads = _d.sent(); elementBox = { x: quads.quads[0][0], y: quads.quads[0][1], width: quads.quads[0][4] - quads.quads[0][0], height: quads.quads[0][5] - quads.quads[0][1] }; if (!!relativeToMainFrame) return [3, 15]; elementFrame = element.executionContext().frame(); if (!(elementFrame != null)) return [3, 4]; return [4, ((_c = elementFrame.parentFrame()) === null || _c === void 0 ? void 0 : _c.$x('//iframe'))]; case 3: _a = _d.sent(); return [3, 5]; case 4: _a = null; _d.label = 5; case 5: iframes = _a; frame = void 0; if (!(iframes != null)) return [3, 13]; _d.label = 6; case 6: _d.trys.push([6, 11, 12, 13]); iframes_1 = __values(iframes), iframes_1_1 = iframes_1.next(); _d.label = 7; case 7: if (!!iframes_1_1.done) return [3, 10]; iframe = iframes_1_1.value; return [4, iframe.contentFrame()]; case 8: if ((_d.sent()) === elementFrame) frame = iframe; _d.label = 9; case 9: iframes_1_1 = iframes_1.next(); return [3, 7]; case 10: return [3, 13]; case 11: e_1_1 = _d.sent(); e_1 = { error: e_1_1 }; return [3, 13]; case 12: try { if (iframes_1_1 && !iframes_1_1.done && (_b = iframes_1.return)) _b.call(iframes_1); } finally { if (e_1) throw e_1.error; } return [7]; case 13: if (!(frame != null)) return [3, 15]; return [4, frame.boundingBox()]; case 14: boundingBox = _d.sent(); elementBox.x = boundingBox !== null ? elementBox.x - boundingBox.x : elementBox.x; elementBox.y = boundingBox !== null ? elementBox.y - boundingBox.y : elementBox.y; _d.label = 15; case 15: return [2, elementBox]; case 16: _1 = _d.sent(); return [4, element.boundingBox()]; case 17: return [2, _d.sent()]; case 18: return [2]; } }); }); }; function path(start, end, spreadOverride) { var defaultWidth = 100; var minSteps = 25; var width = 'width' in end ? end.width : defaultWidth; var curve = (0, math_1.bezierCurve)(start, end, spreadOverride); var length = curve.length() * 0.8; var baseTime = Math.random() * minSteps; var steps = Math.ceil((Math.log2(fitts(length, width) + 1) + baseTime) * 3); var re = curve.getLUT(steps); return clampPositive(re); } exports.path = path; var clampPositive = function (vectors) { var clamp0 = function (elem) { return Math.max(0, elem); }; return vectors.map(function (vector) { return { x: clamp0(vector.x), y: clamp0(vector.y) }; }); }; var overshootThreshold = 500; var shouldOvershoot = function (a, b) { return (0, math_1.magnitude)((0, math_1.direction)(a, b)) > overshootThreshold; }; var createCursor = function (page, start, performRandomMoves) { if (start === void 0) { start = math_1.origin; } if (performRandomMoves === void 0) { performRandomMoves = false; } var overshootSpread = 10; var overshootRadius = 120; var previous = start; var moving = false; var tracePath = function (vectors, abortOnMove) { if (abortOnMove === void 0) { abortOnMove = false; } return __awaiter(void 0, void 0, void 0, function () { var vectors_1, vectors_1_1, v, error_1, e_2_1; var e_2, _a; return __generator(this, function (_b) { switch (_b.label) { case 0: _b.trys.push([0, 7, 8, 9]); vectors_1 = __values(vectors), vectors_1_1 = vectors_1.next(); _b.label = 1; case 1: if (!!vectors_1_1.done) return [3, 6]; v = vectors_1_1.value; _b.label = 2; case 2: _b.trys.push([2, 4, , 5]); if (abortOnMove && moving) { return [2]; } return [4, page.mouse.move(v.x, v.y)]; case 3: _b.sent(); previous = v; return [3, 5]; case 4: error_1 = _b.sent(); if (!page.browser().isConnected()) return [2]; console.debug('Warning: could not move mouse, error message:', error_1); return [3, 5]; case 5: vectors_1_1 = vectors_1.next(); return [3, 1]; case 6: return [3, 9]; case 7: e_2_1 = _b.sent(); e_2 = { error: e_2_1 }; return [3, 9]; case 8: try { if (vectors_1_1 && !vectors_1_1.done && (_a = vectors_1.return)) _a.call(vectors_1); } finally { if (e_2) throw e_2.error; } return [7]; case 9: return [2]; } }); }); }; var randomMove = function (options) { return __awaiter(void 0, void 0, void 0, function () { var rand, _2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 8, , 9]); if (!!moving) return [3, 3]; return [4, (0, exports.getRandomPagePoint)(page)]; case 1: rand = _a.sent(); return [4, tracePath(path(previous, rand), true)]; case 2: _a.sent(); previous = rand; _a.label = 3; case 3: if (!((options === null || options === void 0 ? void 0 : options.moveDelay) !== undefined && options.moveDelay >= 0)) return [3, 5]; return [4, delay(Math.random() * options.moveDelay)]; case 4: _a.sent(); return [3, 7]; case 5: return [4, delay(Math.random() * 2000)]; case 6: _a.sent(); _a.label = 7; case 7: randomMove().then(function (_) { }, function (_) { }); return [3, 9]; case 8: _2 = _a.sent(); console.debug('Warning: stopping random mouse movements'); return [3, 9]; case 9: return [2]; } }); }); }; var actions = { toggleRandomMove: function (random) { moving = !random; }, click: function (selector, options, frame) { return __awaiter(this, void 0, void 0, function () { var error_2; return __generator(this, function (_a) { switch (_a.label) { case 0: actions.toggleRandomMove(false); if (!(selector !== undefined)) return [3, 2]; return [4, actions.move(selector, options, frame)]; case 1: _a.sent(); actions.toggleRandomMove(false); _a.label = 2; case 2: _a.trys.push([2, 7, , 8]); return [4, page.mouse.down()]; case 3: _a.sent(); if (!((options === null || options === void 0 ? void 0 : options.waitForClick) !== undefined)) return [3, 5]; return [4, delay(options.waitForClick)]; case 4: _a.sent(); _a.label = 5; case 5: return [4, page.mouse.up()]; case 6: _a.sent(); return [3, 8]; case 7: error_2 = _a.sent(); console.debug('Warning: could not click mouse, error message:', error_2); return [3, 8]; case 8: if (!((options === null || options === void 0 ? void 0 : options.moveDelay) !== undefined && options.moveDelay >= 0)) return [3, 10]; return [4, delay(Math.random() * options.moveDelay)]; case 9: _a.sent(); return [3, 12]; case 10: return [4, delay(Math.random() * 2000)]; case 11: _a.sent(); _a.label = 12; case 12: actions.toggleRandomMove(true); return [2]; } }); }); }, move: function (selector, options, frame) { var _a; return __awaiter(this, void 0, void 0, function () { var elem, e_3, box, height, width, destination, dimensions, overshooting, to, correction; var _b, _c; return __generator(this, function (_d) { switch (_d.label) { case 0: actions.toggleRandomMove(false); elem = null; if (!(typeof selector === 'string')) return [3, 14]; if (!(selector.startsWith('//') || selector.startsWith('(//'))) return [3, 7]; if (!((options === null || options === void 0 ? void 0 : options.waitForSelector) !== undefined)) return [3, 2]; return [4, page.waitForXPath(selector, { timeout: options.waitForSelector })]; case 1: _d.sent(); _d.label = 2; case 2: if (!(frame !== null && frame !== undefined)) return [3, 4]; return [4, frame.$x(selector)]; case 3: _b = __read.apply(void 0, [_d.sent(), 1]), elem = _b[0]; return [3, 6]; case 4: return [4, page.$x(selector)]; case 5: _c = __read.apply(void 0, [_d.sent(), 1]), elem = _c[0]; _d.label = 6; case 6: return [3, 13]; case 7: if (!((options === null || options === void 0 ? void 0 : options.waitForSelector) !== undefined)) return [3, 9]; return [4, page.waitForSelector(selector, { timeout: options.waitForSelector })]; case 8: _d.sent(); _d.label = 9; case 9: if (!(frame !== null && frame !== undefined)) return [3, 11]; return [4, frame.$(selector)]; case 10: elem = _d.sent(); return [3, 13]; case 11: return [4, page.$(selector)]; case 12: elem = _d.sent(); _d.label = 13; case 13: if (elem === null) { throw new Error("Could not find element with selector \"".concat(selector, "\", make sure you're waiting for the elements with \"puppeteer.waitForSelector\"")); } return [3, 15]; case 14: elem = selector; _d.label = 15; case 15: if (!(((_a = elem._remoteObject) === null || _a === void 0 ? void 0 : _a.objectId) !== undefined)) return [3, 21]; _d.label = 16; case 16: _d.trys.push([16, 18, , 21]); return [4, page._client.send('DOM.scrollIntoViewIfNeeded', { objectId: elem._remoteObject.objectId })]; case 17: _d.sent(); return [3, 21]; case 18: e_3 = _d.sent(); return [4, elem.evaluate(function (e) { return e.scrollIntoView({ behavior: 'smooth' }); })]; case 19: _d.sent(); return [4, new Promise(function (resolve) { return setTimeout(resolve, 2000); })]; case 20: _d.sent(); return [3, 21]; case 21: return [4, getElementBox(page, elem)]; case 22: box = _d.sent(); if (!(box === null)) return [3, 24]; return [4, elem.evaluate(function (el) { return el.getBoundingClientRect(); })]; case 23: box = (_d.sent()); _d.label = 24; case 24: height = box.height, width = box.width; destination = getRandomBoxPoint(box, options); dimensions = { height: height, width: width }; overshooting = shouldOvershoot(previous, destination); to = overshooting ? (0, math_1.overshoot)(destination, overshootRadius) : destination; return [4, tracePath(path(previous, to))]; case 25: _d.sent(); if (!overshooting) return [3, 27]; correction = path(to, __assign(__assign({}, dimensions), destination), overshootSpread); return [4, tracePath(correction)]; case 26: _d.sent(); _d.label = 27; case 27: previous = destination; actions.toggleRandomMove(true); return [2]; } }); }); }, moveTo: function (destination) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: actions.toggleRandomMove(false); return [4, tracePath(path(previous, destination))]; case 1: _a.sent(); actions.toggleRandomMove(true); return [2]; } }); }); } }; if (performRandomMoves) randomMove().then(function (_) { }, function (_) { }); return actions; }; exports.createCursor = createCursor;