| import pino from "pino";
|
| import { Page } from "rebrowser-playwright-core";
|
|
|
| const logger = pino();
|
|
|
| |
| |
| |
| |
|
|
| export const sleep = (x: number, y?: number): Promise<void> => {
|
| let timeout = x * 1000;
|
| if (y !== undefined && y !== x) {
|
| const min = Math.min(x, y);
|
| const max = Math.max(x, y);
|
| timeout = Math.floor(Math.random() * (max - min + 1) + min) * 1000;
|
| }
|
|
|
| logger.info(`Sleeping for ${timeout / 1000} seconds`);
|
|
|
| return new Promise(resolve => setTimeout(resolve, timeout));
|
| }
|
|
|
| |
| |
| |
|
|
| export const isPage = (target: any): target is Page => {
|
| return target.constructor.name === 'Page';
|
| }
|
|
|
| |
| |
| |
| |
| |
|
|
| export const waitForRequests = (page: Page, signal: AbortSignal): Promise<void> => {
|
| return new Promise((resolve, reject) => {
|
| const urlPattern = /^https:\/\/img[a-zA-Z0-9]*\.hcaptcha\.com\/.*$/;
|
| let timeoutHandle: NodeJS.Timeout | null = null;
|
| let activeRequestCount = 0;
|
| let requestOccurred = false;
|
|
|
| const cleanupListeners = () => {
|
| page.off('request', onRequest);
|
| page.off('requestfinished', onRequestFinished);
|
| page.off('requestfailed', onRequestFinished);
|
| };
|
|
|
| const resetTimeout = () => {
|
| if (timeoutHandle)
|
| clearTimeout(timeoutHandle);
|
| if (activeRequestCount === 0) {
|
| timeoutHandle = setTimeout(() => {
|
| cleanupListeners();
|
| resolve();
|
| }, 1000);
|
| }
|
| };
|
|
|
| const onRequest = (request: { url: () => string }) => {
|
| if (urlPattern.test(request.url())) {
|
| requestOccurred = true;
|
| activeRequestCount++;
|
| if (timeoutHandle)
|
| clearTimeout(timeoutHandle);
|
| }
|
| };
|
|
|
| const onRequestFinished = (request: { url: () => string }) => {
|
| if (urlPattern.test(request.url())) {
|
| activeRequestCount--;
|
| resetTimeout();
|
| }
|
| };
|
|
|
|
|
| const initialTimeout = setTimeout(() => {
|
| if (!requestOccurred) {
|
| page.off('request', onRequest);
|
| cleanupListeners();
|
| reject(new Error('No hCaptcha request occurred within 1 minute.'));
|
| } else {
|
|
|
| resetTimeout();
|
| }
|
| }, 60000);
|
|
|
| page.on('request', onRequest);
|
| page.on('requestfinished', onRequestFinished);
|
| page.on('requestfailed', onRequestFinished);
|
|
|
|
|
| page.on('request', (request: { url: () => string }) => {
|
| if (urlPattern.test(request.url())) {
|
| clearTimeout(initialTimeout);
|
| }
|
| });
|
|
|
| const onAbort = () => {
|
| cleanupListeners();
|
| clearTimeout(initialTimeout);
|
| if (timeoutHandle)
|
| clearTimeout(timeoutHandle);
|
| signal.removeEventListener('abort', onAbort);
|
| reject(new Error('AbortError'));
|
| };
|
|
|
| signal.addEventListener('abort', onAbort, { once: true });
|
| });
|
| }
|
|
|
| export const corsHeaders = {
|
| 'Access-Control-Allow-Origin': '*',
|
| 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
| 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
| } |