From 355822169643c171b9213378e121e64efc556deb Mon Sep 17 00:00:00 2001 From: Kevin Damstra <5725258+skoander@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:30:20 +0100 Subject: [PATCH] change playwright implementation --- epic-games.js | 41 +++++++++++++++--------------- package-lock.json | 65 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/epic-games.js b/epic-games.js index 4db1e75..8514ded 100644 --- a/epic-games.js +++ b/epic-games.js @@ -1,9 +1,10 @@ -import { firefox } from 'playwright-firefox'; // stealth plugin needs no outdated playwright-extra +// import { firefox } from 'playwright-firefox'; // stealth plugin needs no outdated playwright-extra +import { chromium } from 'patchright'; import { authenticator } from 'otplib'; import chalk from 'chalk'; import path from 'path'; import { existsSync, writeFileSync, appendFileSync } from 'fs'; -import { resolve, jsonDb, datetime, stealth, filenamify, prompt, notify, html_game_list, handleSIGINT } from './src/util.js'; +import { resolve, jsonDb, datetime, filenamify, prompt, notify, html_game_list, handleSIGINT } from './src/util.js'; import { cfg } from './src/config.js'; const screenshot = (...a) => resolve(cfg.dir.screenshots, 'epic-games', ...a); @@ -26,31 +27,17 @@ if (existsSync(browserPrefs)) { } // https://playwright.dev/docs/auth#multi-factor-authentication -const context = await firefox.launchPersistentContext(cfg.dir.browser, { - headless: cfg.headless, - viewport: { width: cfg.width, height: cfg.height }, - userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0', // see replace of Headless in util.newStealthContext. TODO Windows UA enough to avoid 'device not supported'? update if browser is updated? - // userAgent firefox (macOS): Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:106.0) Gecko/20100101 Firefox/106.0 - // userAgent firefox (docker): Mozilla/5.0 (X11; Linux aarch64; rv:109.0) Gecko/20100101 Firefox/115.0 - locale: 'en-US', // ignore OS locale to be sure to have english text for locators - recordVideo: cfg.record ? { dir: 'data/record/', size: { width: cfg.width, height: cfg.height } } : undefined, // will record a .webm video for each page navigated; without size, video would be scaled down to fit 800x800 - recordHar: cfg.record ? { path: `data/record/eg-${filenamify(datetime())}.har` } : undefined, // will record a HAR file with network requests and responses; can be imported in Chrome devtools - handleSIGINT: false, // have to handle ourselves and call context.close(), otherwise recordings from above won't be saved - // user settings for firefox have to be put in $BROWSER_DIR/user.js - args: [ // https://wiki.mozilla.org/Firefox/CommandLineOptions - // '-kiosk', - ], +const context = await chromium.launchPersistentContext(cfg.dir.browser, { + channel: 'chrome', + headless: false, + viewport: null, }); handleSIGINT(context); -// Without stealth plugin, the website shows an hcaptcha on login with username/password and in the last step of claiming a game. It may have other heuristics like unsuccessful logins as well. After <6h (TBD) it resets to no captcha again. Getting a new IP also resets. -await stealth(context); - if (!cfg.debug) context.setDefaultTimeout(cfg.timeout); const page = context.pages().length ? context.pages()[0] : await context.newPage(); // should always exist -await page.setViewportSize({ width: cfg.width, height: cfg.height }); // TODO workaround for https://github.com/vogler/free-games-claimer/issues/277 until Playwright fixes it // some debug info about the page (screen dimensions, user agent, platform) // eslint-disable-next-line no-undef @@ -107,13 +94,24 @@ try { console.error('Incorrect response for captcha!'); }).catch(_ => { }); await page.fill('#email', email); - // await page.click('button[type="submit"]'); login was split in two steps for some time, now email and password are on the same form again + await page.click('button[type="submit"]'); const password = email && (cfg.eg_password || await prompt({ type: 'password', message: 'Enter password' })); if (!password) await notifyBrowserLogin(); else { await page.fill('#password', password); + console.info('Filled in email and password.'); + await page.waitForTimeout(2000); // Waits for 2 seconds + console.info('Submitting login form...'); + await page.click('button[type="submit"]'); + await page.waitForTimeout(5000); // Waits for 2 seconds + } + // find h1 with text 'Is this the right account?' + const accountHeader = page.locator('h1:has-text("Is this the right account?")'); + // if accountHeader exists, click button type submit + if (await accountHeader.count() > 0) { await page.click('button[type="submit"]'); } + const error = page.locator('#form-error-message'); error.waitFor().then(async () => { console.error('Login error:', await error.innerText()); @@ -125,6 +123,7 @@ try { // TODO locator for text (email or app?) const otp = cfg.eg_otpkey && authenticator.generate(cfg.eg_otpkey) || await prompt({ type: 'text', message: 'Enter two-factor sign in code', validate: n => n.toString().length == 6 || 'The code must be 6 digits!' }); // can't use type: 'number' since it strips away leading zeros and codes sometimes have them await page.locator('input[name="code-input-0"]').pressSequentially(otp.toString()); + await page.waitForTimeout(3000); // Waits for 3 seconds await page.click('button[type="submit"]'); }).catch(_ => { }); } diff --git a/package-lock.json b/package-lock.json index 9ab1fff..f4510cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "fingerprint-injector": "^2.1.66", "lowdb": "^7.0.1", "otplib": "^12.0.1", + "patchright": "^1.56.1", "playwright-firefox": "^1.52.0", "puppeteer-extra-plugin-stealth": "^2.11.2" }, @@ -1386,6 +1387,20 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2138,6 +2153,36 @@ "node": ">= 0.8" } }, + "node_modules/patchright": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/patchright/-/patchright-1.56.1.tgz", + "integrity": "sha512-HY4s3vJNPVoasoy0X7sOm2dufQwlicvXoCpoINYFUWYkEaSBM2l4UtSOdI4/MYQHNskfOFpIqE+Usj748qbtYg==", + "license": "Apache-2.0", + "dependencies": { + "patchright-core": "1.56.1" + }, + "bin": { + "patchright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/patchright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/patchright-core/-/patchright-core-1.56.1.tgz", + "integrity": "sha512-ot1WU31T+FLjBg8LUbEnPPhzh6uRYji25ZONHpxVUEXtANuVJf6tI4nv6jw6n37qsjgS4u12sq7Go0Vdte3JJQ==", + "license": "Apache-2.0", + "bin": { + "patchright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3786,6 +3831,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4301,6 +4352,20 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, + "patchright": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/patchright/-/patchright-1.56.1.tgz", + "integrity": "sha512-HY4s3vJNPVoasoy0X7sOm2dufQwlicvXoCpoINYFUWYkEaSBM2l4UtSOdI4/MYQHNskfOFpIqE+Usj748qbtYg==", + "requires": { + "fsevents": "2.3.2", + "patchright-core": "1.56.1" + } + }, + "patchright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/patchright-core/-/patchright-core-1.56.1.tgz", + "integrity": "sha512-ot1WU31T+FLjBg8LUbEnPPhzh6uRYji25ZONHpxVUEXtANuVJf6tI4nv6jw6n37qsjgS4u12sq7Go0Vdte3JJQ==" + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", diff --git a/package.json b/package.json index 0487277..bba67a1 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "fingerprint-injector": "^2.1.66", "lowdb": "^7.0.1", "otplib": "^12.0.1", + "patchright": "^1.56.1", "playwright-firefox": "^1.52.0", "puppeteer-extra-plugin-stealth": "^2.11.2" },