
- fixed bug in dragging type of hCaptcha when worker did not select an even amount of coordinates and it would crash - change waitForResponse function to a waitForRequests util function with more proper checks
118 lines
3.5 KiB
TypeScript
118 lines
3.5 KiB
TypeScript
import pino from "pino";
|
|
import { Page } from "rebrowser-playwright-core";
|
|
|
|
const logger = pino();
|
|
|
|
/**
|
|
* Pause for a specified number of seconds.
|
|
* @param x Minimum number of seconds.
|
|
* @param y Maximum number of seconds (optional).
|
|
*/
|
|
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;
|
|
}
|
|
// console.log(`Sleeping for ${timeout / 1000} seconds`);
|
|
logger.info(`Sleeping for ${timeout / 1000} seconds`);
|
|
|
|
return new Promise(resolve => setTimeout(resolve, timeout));
|
|
}
|
|
|
|
/**
|
|
* @param target A Locator or a page
|
|
* @returns {boolean}
|
|
*/
|
|
export const isPage = (target: any): target is Page => {
|
|
return target.constructor.name === 'Page';
|
|
}
|
|
|
|
/**
|
|
* Waits for an hCaptcha image requests and then waits for all of them to end
|
|
* @param page
|
|
* @param signal `const controller = new AbortController(); controller.status`
|
|
* @returns {Promise<void>}
|
|
*/
|
|
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); // 1 second of no requests
|
|
}
|
|
};
|
|
|
|
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();
|
|
}
|
|
};
|
|
|
|
// Wait for an hCaptcha request for up to 1 minute
|
|
const initialTimeout = setTimeout(() => {
|
|
if (!requestOccurred) {
|
|
page.off('request', onRequest);
|
|
cleanupListeners();
|
|
reject(new Error('No hCaptcha request occurred within 1 minute.'));
|
|
} else {
|
|
// Start waiting for no hCaptcha requests
|
|
resetTimeout();
|
|
}
|
|
}, 60000); // 1 minute timeout
|
|
|
|
page.on('request', onRequest);
|
|
page.on('requestfinished', onRequestFinished);
|
|
page.on('requestfailed', onRequestFinished);
|
|
|
|
// Cleanup the initial timeout if an hCaptcha request occurs
|
|
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',
|
|
} |