epic-games: catch timeout and save screenshot of hcaptcha

This commit is contained in:
Ralf Vogler 2022-02-02 12:50:53 +01:00
parent b078398e48
commit 3766754a5f
3 changed files with 20 additions and 8 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@ node_modules/
auth.json
.env
userDataDir/
screenshots/

View file

@ -28,7 +28,7 @@ Claiming the Amazon Games works, external Epic Games also work if the account is
Origin needs testing - it shows a key, which should be printed to the console, but the selector may be wrong.
Other stores not tested.
## Log
## DevLog
Tried [epicgames-freebies-claimer](https://github.com/Revadike/epicgames-freebies-claimer), but does not work anymore since epicgames introduced hcaptcha (see [issue](https://github.com/Revadike/epicgames-freebies-claimer/issues/172)).
@ -43,7 +43,7 @@ Also, solving via [2captcha](https://2captcha.com?from=13225256) is a paid servi
<!-- Alternative: https://anti-captcha.com -->
Added [main.stealth.js](https://github.com/vogler/epicgames-claimer/commit/64d0ba8ce71baec3947d1b64acd567befcb39340#diff-f70d3bd29df4a343f11062a97063953173491ce30fe34f69a0fc52517adbf342) which uses the stealth plugin without `playwright-extra` wrapper but up-to-date `playwright` (from [comment](https://github.com/berstend/puppeteer-extra/issues/454#issuecomment-917437212)).
The listed evasions are enough to not show an hcaptcha. Script claimed game successfully in headful mode.
The listed evasions are enough to not show an hcaptcha. Script claimed game successfully in non-headless mode.
Removed `main.captcha.js`.
Using Playwright Test (`main.spec.ts`) instead of Library (`main.stealth.js`) has the advantage of free CLI like `--debug` and `--timeout`.
@ -52,3 +52,5 @@ Using Playwright Test (`main.spec.ts`) instead of Library (`main.stealth.js`) ha
Button selectors should preferably use text in order to be more stable against changes in the DOM.
Renamed repository from epicgames-claimer to free-games-claimer since a script for Amazon Prime Gaming was also added. Removed all old scripts in favor of just `epic-games.js` and `prime-gaming.js`.
epic games: `headless` mode gets hcaptcha challenge. More details/references in [issue](https://github.com/vogler/free-games-claimer/issues/2).

View file

@ -1,7 +1,7 @@
//@ts-check
const { chromium } = require('playwright'); // stealth plugin needs no outdated playwright-extra
const path = require('path');
const debug = process.env.PWDEBUG == '1'; // runs headful and opens https://playwright.dev/docs/inspector
const debug = process.env.PWDEBUG == '1'; // runs non-headless and opens https://playwright.dev/docs/inspector
const URL_LOGIN = 'https://www.epicgames.com/login';
const URL_CLAIM = 'https://www.epicgames.com/store/en-US/free-games';
@ -64,7 +64,7 @@ const TIMEOUT = 20 * 1000; // 20s, default is 30s
await page.goto(URL_CLAIM, {waitUntil: 'domcontentloaded'}); // default 'load' takes forever
// with persistent context the cookie message will only show up the first time, so we can't unconditionally wait for it - try to catch it or let the user click it.
await clickIfExists('button:has-text("Accept All Cookies")'); // to not waste screen space in --debug
while (await page.locator('a[role="button"]:has-text("Sign In")').count() > 0) {
while (await page.locator('a[role="button"]:has-text("Sign In")').count() > 0) { // TODO also check alternative for signed-in state
console.error("Not signed in anymore. Please login and then navigate to the 'Free Games' page.");
context.setDefaultTimeout(0); // give user time to log in without timeout
await page.goto(URL_LOGIN, {waitUntil: 'domcontentloaded'});
@ -96,7 +96,6 @@ const TIMEOUT = 20 * 1000; // 20s, default is 30s
console.log('Not in library yet! Click GET.')
await page.click('[data-testid="purchase-cta-button"]');
// click Continue if 'Device not supported. This product is not compatible with your current device.'
// await page.waitForTimeout(1000); // wait for 1s since count does not wait.
// @ts-ignore https://caniuse.com/?search=promise.any
await Promise.any([':has-text("Continue")', '#webPurchaseContainer iframe'].map(s => page.waitForSelector(s))); // wait for Continue xor iframe
if (await page.locator(':has-text("Continue")').count() > 0) {
@ -107,15 +106,25 @@ const TIMEOUT = 20 * 1000; // 20s, default is 30s
// await page.frame({ url: /.*store\/purchase.*/ }).click('button:has-text("Place Order")'); // not found because it does not wait for iframe
const iframe = page.frameLocator('#webPurchaseContainer iframe')
await iframe.locator('button:has-text("Place Order")').click();
// await page.pause();
await iframe.locator('button:has-text("I Agree")').click();
// This is true even when there is no captcha shown! That was the reason why old.stealth.js worked - it did not have this check... TODO check for hcaptcha
// This is true even when there is no captcha challenge shown! That was the reason why old.stealth.js worked - it did not have this check... TODO check for hcaptcha
// if (await iframe.frameLocator('#talon_frame_checkout_free_prod').locator('text=Please complete a security check to continue').count() > 0) {
// console.error('Encountered hcaptcha. Giving up :(');
// await page.pause();
// process.exit(1);
// }
await page.waitForSelector('text=Thank you for buying');
console.log('Claimed successfully!');
// await page.waitForTimeout(3000);
try {
await page.waitForSelector('text=Thank you for buying');
console.log('Claimed successfully!');
} catch (e) {
console.log(e);
const p = `screenshots/${new Date().toISOString()}.png`;
await page.screenshot({ path: p, fullPage: true })
console.info('Saved a screenshot of hcaptcha challenge to', p);
console.error('Got hcaptcha challenge. To avoid it, get a link from https://www.hcaptcha.com/accessibility'); // TODO save this link in config and visit it daily to set accessibility cookie to avoid captcha challenge?
}
// await page.pause();
}
if (i<n) { // no need to go back if it's the last game