From e2b07dc1e64add66d74dd74fce5918492e179c2d Mon Sep 17 00:00:00 2001 From: Ralf Vogler Date: Thu, 16 Feb 2023 16:10:28 +0100 Subject: [PATCH] BROWSER_DIR for multiple profiles or testing, SCREENSHOTS_DIR, closes #12 --- README.md | 1 + config.js | 8 ++++++++ epic-games.js | 12 ++++++------ gog.js | 6 +++--- prime-gaming.js | 10 +++++----- util.js | 8 +------- 6 files changed, 24 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index b3da0ed..5e85f1e 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ Available options/variables and their default values: | HEIGHT | 1280 | Height of the opened browser (and screen vor VNC in Docker). | | VNC_PASSWORD | | VNC password for Docker. No password used by default! | | NOTIFY | | Notification services to use (Pushover, Slack, Telegram...), see below. | +| BROWSER_DIR | data/browser | Directory for browser profile, e.g. for multiple accounts. | | EMAIL | | Default email for any login. | | PASSWORD | | Default password for any login. | | EG_EMAIL | | Epic Games email for login. Overrides EMAIL. | diff --git a/config.js b/config.js index 726e6bd..e7408d4 100644 --- a/config.js +++ b/config.js @@ -1,4 +1,6 @@ import * as dotenv from 'dotenv'; +import { dataDir } from './util.js'; + dotenv.config({ path: 'data/config.env' }); // loads env vars from file - will not set vars that are already set, i.e., can overwrite values from file by prefixing, e.g., VAR=VAL node ... // Options - also see table in README.md @@ -12,6 +14,12 @@ export const cfg = { timeout: (Number(process.env.TIMEOUT) || 20) * 1000, // 20s, default for playwright is 30s novnc_port: process.env.NOVNC_PORT, // running in docker if set notify: process.env.NOTIFY, // apprise notification services + get dir() { // avoids ReferenceError: Cannot access 'dataDir' before initialization + return { + browser: process.env.BROWSER_DIR || dataDir('browser'), // for multiple accounts or testing + screenshots: process.env.SCREENSHOTS_DIR || dataDir('screenshots'), // if not wanted: /dev/null + } + }, // auth epic-games eg_email: process.env.EG_EMAIL || process.env.EMAIL, eg_password: process.env.EG_PASSWORD || process.env.PASSWORD, diff --git a/epic-games.js b/epic-games.js index 70a379d..aed786d 100644 --- a/epic-games.js +++ b/epic-games.js @@ -2,7 +2,7 @@ import { firefox } from 'playwright'; // stealth plugin needs no outdated playwr import { authenticator } from 'otplib'; import path from 'path'; import { existsSync, writeFileSync } from 'fs'; -import { dirs, jsonDb, datetime, stealth, filenamify, prompt, notify, html_game_list } from './util.js'; +import { jsonDb, datetime, stealth, filenamify, prompt, notify, html_game_list } from './util.js'; import { cfg } from './config.js'; const URL_CLAIM = 'https://store.epicgames.com/en-US/free-games'; @@ -17,7 +17,7 @@ db.data ||= {}; // const ext = path.resolve('nopecha'); // used in Chromium, currently not needed in Firefox // https://playwright.dev/docs/auth#multi-factor-authentication -const context = await firefox.launchPersistentContext(dirs.browser, { +const context = await firefox.launchPersistentContext(cfg.dir.browser, { // chrome will not work in linux arm64, only chromium // channel: 'chrome', // https://playwright.dev/docs/browsers#google-chrome--microsoft-edge headless: cfg.headless, @@ -156,7 +156,7 @@ try { // console.info(' Got hcaptcha challenge! NopeCHA extension will likely solve it.') console.error(' Got hcaptcha challenge! Lost trust due to too many login attempts? You can solve the captcha in the browser or get a new IP address.') // await page.waitForTimeout(2000); - // const p = path.resolve(dirs.screenshots, 'epic-games', 'captcha', `${filenamify(datetime())}.png`); + // const p = path.resolve(cfg.dir.screenshots, 'epic-games', 'captcha', `${filenamify(datetime())}.png`); // await captcha.screenshot({ path: p }); // 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? @@ -170,13 +170,13 @@ try { console.log(e); // console.error(' Failed to claim! Try again if NopeCHA timed out. Click the extension to see if you ran out of credits (refill after 24h). To avoid captchas try to get a new IP or set a cookie from https://www.hcaptcha.com/accessibility'); console.error(' Failed to claim! To avoid captchas try to get a new IP address.'); - const p = path.resolve(dirs.screenshots, 'epic-games', 'failed', `${game_id}_${filenamify(datetime())}.png`); + const p = path.resolve(cfg.dir.screenshots, 'epic-games', 'failed', `${game_id}_${filenamify(datetime())}.png`); await page.screenshot({ path: p, fullPage: true }); db.data[user][game_id].status = 'failed'; } notify_game.status = db.data[user][game_id].status; // claimed or failed - const p = path.resolve(dirs.screenshots, 'epic-games', `${game_id}.png`); + const p = path.resolve(cfg.dir.screenshots, 'epic-games', `${game_id}.png`); if (!existsSync(p)) await page.screenshot({ path: p, fullPage: false }); // fullPage is quite long... } } @@ -190,5 +190,5 @@ try { notify(`epic-games:
${html_game_list(notify_games)}`); } } -writeFileSync(path.resolve(dirs.browser, 'cookies.json'), JSON.stringify(await context.cookies())); +writeFileSync(path.resolve(cfg.dir.browser, 'cookies.json'), JSON.stringify(await context.cookies())); await context.close(); diff --git a/gog.js b/gog.js index 7dc9aa0..044557c 100644 --- a/gog.js +++ b/gog.js @@ -1,6 +1,6 @@ import { firefox } from 'playwright'; // stealth plugin needs no outdated playwright-extra import path from 'path'; -import { dirs, jsonDb, datetime, filenamify, prompt, notify, html_game_list } from './util.js'; +import { jsonDb, datetime, filenamify, prompt, notify, html_game_list } from './util.js'; import { cfg } from './config.js'; const URL_CLAIM = 'https://www.gog.com/en'; @@ -11,7 +11,7 @@ const db = await jsonDb('gog.json'); db.data ||= {}; // https://playwright.dev/docs/auth#multi-factor-authentication -const context = await firefox.launchPersistentContext(dirs.browser, { +const context = await firefox.launchPersistentContext(cfg.dir.browser, { headless: cfg.headless, viewport: { width: cfg.width, height: cfg.height }, locale: "en-US", // ignore OS locale to be sure to have english text for locators -> done via /en in URL @@ -93,7 +93,7 @@ try { console.log(`Current free game: ${title} - ${url}`); db.data[user][title] ||= { title, time: datetime(), url }; if (cfg.dryrun) process.exit(1); - const p = path.resolve(dirs.screenshots, 'gog', `${filenamify(title)}.png`); + const p = path.resolve(cfg.dir.screenshots, 'gog', `${filenamify(title)}.png`); await banner.screenshot({ path: p }); // overwrites every time - only keep first? // await banner.getByRole('button', { name: 'Add to library' }).click(); diff --git a/prime-gaming.js b/prime-gaming.js index 2001361..1320992 100644 --- a/prime-gaming.js +++ b/prime-gaming.js @@ -1,7 +1,7 @@ import { firefox } from 'playwright'; // stealth plugin needs no outdated playwright-extra import { authenticator } from 'otplib'; import path from 'path'; -import { dirs, jsonDb, datetime, stealth, filenamify, prompt, notify, html_game_list } from './util.js'; +import { jsonDb, datetime, stealth, filenamify, prompt, notify, html_game_list } from './util.js'; import { cfg } from './config.js'; // const URL_LOGIN = 'https://www.amazon.de/ap/signin'; // wrong. needs some session args to be valid? @@ -13,7 +13,7 @@ const db = await jsonDb('prime-gaming.json'); db.data ||= {}; // https://playwright.dev/docs/auth#multi-factor-authentication -const context = await firefox.launchPersistentContext(dirs.browser, { +const context = await firefox.launchPersistentContext(cfg.dir.browser, { headless: cfg.headless, viewport: { width: cfg.width, height: cfg.height }, locale: "en-US", // ignore OS locale to be sure to have english text for locators @@ -98,7 +98,7 @@ try { if (cfg.dryrun) continue; // const img = await (await card.$('img.tw-image')).getAttribute('src'); // console.log('Image:', img); - const p = path.resolve(dirs.screenshots, 'prime-gaming', 'internal', `${filenamify(title)}.png`); + const p = path.resolve(cfg.dir.screenshots, 'prime-gaming', 'internal', `${filenamify(title)}.png`); await card.screenshot({ path: p }); await (await card.$('button:has-text("Claim game")')).click(); db.data[user][title] ||= { title, time: datetime(), store: 'internal' }; @@ -150,7 +150,7 @@ try { notify_game.status = `claimed on ${store}`; } // save screenshot of potential code just in case - const p = path.resolve(dirs.screenshots, 'prime-gaming', 'external', `${filenamify(title)}.png`); + const p = path.resolve(cfg.dir.screenshots, 'prime-gaming', 'external', `${filenamify(title)}.png`); await page.screenshot({ path: p, fullPage: true }); // console.info(' Saved a screenshot of page to', p); } @@ -158,7 +158,7 @@ try { await page.goto(URL_CLAIM, { waitUntil: 'domcontentloaded' }); await page.click('button[data-type="Game"]'); } while (n); - const p = path.resolve(dirs.screenshots, 'prime-gaming', `${filenamify(datetime())}.png`); + const p = path.resolve(cfg.dir.screenshots, 'prime-gaming', `${filenamify(datetime())}.png`); // await page.screenshot({ path: p, fullPage: true }); await page.locator(games_sel).screenshot({ path: p }); } catch (error) { diff --git a/util.js b/util.js index f2123a0..d64b94b 100644 --- a/util.js +++ b/util.js @@ -5,13 +5,7 @@ import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // explicit object instead of Object.fromEntries since the built-in type would loose the keys, better type: https://dev.to/svehla/typescript-object-fromentries-389c -const dataDir = s => path.resolve(__dirname, 'data', s); -export const dirs = { - data: dataDir('.'), - browser: dataDir('browser'), - screenshots: dataDir('screenshots'), -}; - +export const dataDir = s => path.resolve(__dirname, 'data', s); // json database import { Low } from 'lowdb';