suno-api/src/lib/utils.ts
gohoski 881c6c773c changed wait for hCaptcha image logic & other stuff
- 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
2025-01-11 01:48:17 +03:00

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',
}