diff --git a/src/config.ts b/src/config.ts index aa2672ddf3..9380b238e7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -197,6 +197,7 @@ const notifications = { 3070: envOrArray(process.env.DISCORD_NOTIFY_GROUP_3070), 3080: envOrArray(process.env.DISCORD_NOTIFY_GROUP_3080), 3090: envOrArray(process.env.DISCORD_NOTIFY_GROUP_3090), + 'captcha-deterrent': [], darkhero: envOrArray(process.env.DISCORD_NOTIFY_GROUP_DARKHERO), rx6800: envOrArray(process.env.DISCORD_NOTIFY_GROUP_RX6800), rx6800xt: envOrArray(process.env.DISCORD_NOTIFY_GROUP_RX6800XT), @@ -348,6 +349,7 @@ const store = { 3070: envOrNumber(process.env.MAX_PRICE_SERIES_3070), 3080: envOrNumber(process.env.MAX_PRICE_SERIES_3080), 3090: envOrNumber(process.env.MAX_PRICE_SERIES_3090), + 'captcha-deterrent': 0, darkhero: envOrNumber(process.env.MAX_PRICE_SERIES_DARKHERO), rx6800: envOrNumber(process.env.MAX_PRICE_SERIES_RX6800), rx6800xt: envOrNumber(process.env.MAX_PRICE_SERIES_RX6800XT), diff --git a/src/store/lookup.ts b/src/store/lookup.ts index ab53f76400..1edc71d75e 100644 --- a/src/store/lookup.ts +++ b/src/store/lookup.ts @@ -234,6 +234,10 @@ async function lookup(browser: Browser, store: Store) { } catch {} }); + if (store.captchaDeterrent) { + await runCaptchaDeterrent(browser, store, page); + } + let statusCode = 0; try { @@ -477,6 +481,75 @@ async function lookupCardInStock(store: Store, page: Page, link: Link) { return true; } +async function runCaptchaDeterrent(browser: Browser, store: Store, page: Page) { + const successStatusCodes = store.successStatusCodes ?? [[0, 399]]; + let statusCode = 0; + let deterrentLinks: string[] = []; + + logger.debug(`[${store.name}] Navigating to random anti-captcha page...`); + + if (store.captchaDeterrent?.hardLinks?.length) { + deterrentLinks = deterrentLinks.concat( + store.captchaDeterrent.hardLinks + ); + } + + if (store.captchaDeterrent?.searchUrl) { + if (store.captchaDeterrent.searchTerms) { + store.captchaDeterrent.searchTerms.forEach((element) => + deterrentLinks.push( + store.captchaDeterrent?.searchUrl + ? store.captchaDeterrent.searchUrl.replace( + '%%s', + element + ) + : '' + ) + ); + } + } + + if (deterrentLinks.length > 0) { + const link: Link = { + brand: 'captcha-deterrent', + model: 'captcha-deterrent', + series: 'captcha-deterrent', + url: + deterrentLinks[ + Math.floor(Math.random() * deterrentLinks.length) + ] + }; + logger.debug(`Selected captcha-deterrent link: ${link.url}`); + + try { + const givenWaitFor = store.waitUntil + ? store.waitUntil + : 'networkidle0'; + const response: Response | null = await page.goto(link.url, { + waitUntil: givenWaitFor + }); + statusCode = await handleResponse( + browser, + store, + page, + link, + response + ); + setTimeout(() => { + // Do nothing + }, 3000); + } catch (error: unknown) { + logger.error(error); + } + + if (!isStatusCodeInRange(statusCode, successStatusCodes)) { + logger.warn( + `✖ [${store.name}] - Failed to navigate to anti-captcha target: ${link.url}` + ); + } + } +} + export async function tryLookupAndLoop(browser: Browser, store: Store) { if (!browser.isConnected()) { logger.debug( diff --git a/src/store/model/amazon.ts b/src/store/model/amazon.ts index 5235ebcba1..fc38dd657c 100644 --- a/src/store/model/amazon.ts +++ b/src/store/model/amazon.ts @@ -2,6 +2,16 @@ import {Store} from './store'; export const Amazon: Store = { backoffStatusCodes: [403, 429, 503], + captchaDeterrent: { + hardLinks: [ + 'https://www.amazon.com/Amazon-Video/b/?ie=UTF8&node=2858778011&ref_=nav_cs_prime_video', + 'https://www.amazon.com/alm/storefront?almBrandId=VUZHIFdob2xlIEZvb2Rz&ref_=nav_cs_whole_foods_in_region', + 'https://www.amazon.com/gp/goldbox?ref_=nav_cs_gb' + ], + searchTerms: ['goober', 'dungeons+and+dragons'], + searchUrl: + 'https://www.amazon.com/s?k=%%s&i=todays-deals&ref=nb_sb_noss_2' + }, currency: '$', labels: { captcha: { diff --git a/src/store/model/store.ts b/src/store/model/store.ts index ade33aa144..ec0174ad66 100644 --- a/src/store/model/store.ts +++ b/src/store/model/store.ts @@ -12,6 +12,7 @@ export type Pricing = { export type Brand = | 'test:brand' + | 'captcha-deterrent' | 'amd' | 'asrock' | 'asus' @@ -37,6 +38,7 @@ export type Brand = export type Series = | 'test:series' + | 'captcha-deterrent' | '3060ti' | '3070' | '3080' @@ -57,6 +59,7 @@ export type Series = export type Model = | 'test:model' + | 'captcha-deterrent' | '5600x' | '5800x' | '5900x' @@ -181,6 +184,12 @@ export type Labels = { maxPrice?: Pricing; }; +export type CaptchaDeterrent = { + hardLinks?: string[]; + searchUrl?: string; + searchTerms?: string[]; +}; + export type StatusCodeRangeArray = Array; export type Store = { @@ -215,4 +224,6 @@ export type Store = { proxyList?: string[]; currentProxyIndex?: number; + + captchaDeterrent?: CaptchaDeterrent; };