pg: notify about games and login

This commit is contained in:
Ralf Vogler 2023-01-25 18:54:23 +01:00
parent 95b703efb1
commit 13e6f05cd0
2 changed files with 23 additions and 7 deletions

View file

@ -194,7 +194,7 @@ try {
} }
} catch (error) { } catch (error) {
console.error(error); // .toString()? console.error(error); // .toString()?
if (!error.message.contains('Target closed')) // e.g. when killed by Ctrl-C if (error.message && !error.message.contains('Target closed')) // e.g. when killed by Ctrl-C
notify(`epic-games failed: ${error.message}`); notify(`epic-games failed: ${error.message}`);
} finally { } finally {
await db.write(); // write out json db await db.write(); // write out json db

View file

@ -1,7 +1,7 @@
import { firefox } from 'playwright'; // stealth plugin needs no outdated playwright-extra import { firefox } from 'playwright'; // stealth plugin needs no outdated playwright-extra
import { authenticator } from 'otplib'; import { authenticator } from 'otplib';
import path from 'path'; import path from 'path';
import { dirs, jsonDb, datetime, stealth, filenamify } from './util.js'; import { dirs, jsonDb, datetime, stealth, filenamify, notify } from './util.js';
import { cfg } from './config.js'; import { cfg } from './config.js';
import prompts from 'prompts'; // alternatives: enquirer, inquirer import prompts from 'prompts'; // alternatives: enquirer, inquirer
@ -41,6 +41,8 @@ if (!cfg.debug) context.setDefaultTimeout(cfg.timeout);
const page = context.pages().length ? context.pages()[0] : await context.newPage(); // should always exist const page = context.pages().length ? context.pages()[0] : await context.newPage(); // should always exist
// console.debug('userAgent:', await page.evaluate(() => navigator.userAgent)); // console.debug('userAgent:', await page.evaluate(() => navigator.userAgent));
const notify_games = [];
try { try {
await page.goto(URL_CLAIM, { waitUntil: 'domcontentloaded' }); // default 'load' takes forever await page.goto(URL_CLAIM, { waitUntil: 'domcontentloaded' }); // default 'load' takes forever
// need to wait for some elements to exist before checking if signed in or accepting cookies: // need to wait for some elements to exist before checking if signed in or accepting cookies:
@ -60,7 +62,7 @@ try {
await page.click('input[type="submit"]'); await page.click('input[type="submit"]');
page.waitForNavigation({ url: '**/ap/signin**'}).then(async () => { // TODO check for wrong credentials page.waitForNavigation({ url: '**/ap/signin**'}).then(async () => { // TODO check for wrong credentials
console.error(await page.locator('.a-alert-content').first().innerText()); console.error(await page.locator('.a-alert-content').first().innerText());
}).catch(_ => { }); });
// handle MFA, but don't await it // handle MFA, but don't await it
page.waitForNavigation({ url: '**/ap/mfa**'}).then(async () => { page.waitForNavigation({ url: '**/ap/mfa**'}).then(async () => {
console.log('Two-Step Verification - enter the One Time Password (OTP), e.g. generated by your Authenticator App'); console.log('Two-Step Verification - enter the One Time Password (OTP), e.g. generated by your Authenticator App');
@ -70,12 +72,13 @@ try {
await page.click('input[type="submit"]'); await page.click('input[type="submit"]');
}).catch(_ => { }); }).catch(_ => { });
} else { } else {
console.log('Waiting for you to login in the browser.');
notify('prime-gaming: no longer signed in and not enough options set for automatic login.');
if (cfg.headless) { if (cfg.headless) {
console.log('Please run `node prime-gaming show` to login in the opened browser.'); console.log('Please run `node prime-gaming show` to login in the opened browser.');
await context.close(); // not needed? await context.close(); // not needed?
process.exit(1); process.exit(1);
} }
console.log('Waiting for you to login in the browser.');
} }
await page.waitForNavigation({ url: 'https://gaming.amazon.com/home?signedIn=true' }); await page.waitForNavigation({ url: 'https://gaming.amazon.com/home?signedIn=true' });
if (!cfg.debug) context.setDefaultTimeout(cfg.timeout); if (!cfg.debug) context.setDefaultTimeout(cfg.timeout);
@ -108,6 +111,7 @@ try {
await card.screenshot({ path: p }); await card.screenshot({ path: p });
await (await card.$('button:has-text("Claim game")')).click(); await (await card.$('button:has-text("Claim game")')).click();
db.data[user][title] ||= { title, time: datetime(), store: 'internal' }; db.data[user][title] ||= { title, time: datetime(), store: 'internal' };
notify_games.push({ title, status: 'claimed', url: URL_CLAIM });
// await page.pause(); // await page.pause();
} }
// claim games in external/linked stores. Linked: origin.com, epicgames.com; Redeem-key: gog.com, legacygames.com, microsoft // claim games in external/linked stores. Linked: origin.com, epicgames.com; Redeem-key: gog.com, legacygames.com, microsoft
@ -129,6 +133,10 @@ try {
// 3 Full PC Games on Legacy Games // 3 Full PC Games on Legacy Games
const store = store_text.toLowerCase().replace(/.* on /, ''); const store = store_text.toLowerCase().replace(/.* on /, '');
console.log(' External store:', store); console.log(' External store:', store);
const url = page.url().split('?')[0];
db.data[user][title] ||= { title, time: datetime(), url, store };
const notify_game = {title, url, status: `failed - link ${store}`};
notify_games.push(notify_game); // status is updated below
if (await page.locator('div:has-text("Link game account")').count()) { if (await page.locator('div:has-text("Link game account")').count()) {
console.error(' Account linking is required to claim this offer!'); console.error(' Account linking is required to claim this offer!');
} else { } else {
@ -139,16 +147,18 @@ try {
'legacy games': 'https://www.legacygames.com/primedeal', 'legacy games': 'https://www.legacygames.com/primedeal',
'microsoft games': 'https://redeem.microsoft.com', 'microsoft games': 'https://redeem.microsoft.com',
}; };
let code;
if (store in redeem) { // did not work for linked origin: && !await page.locator('div:has-text("Successfully Claimed")').count() if (store in redeem) { // did not work for linked origin: && !await page.locator('div:has-text("Successfully Claimed")').count()
code = await page.inputValue('input[type="text"]'); const code = await page.inputValue('input[type="text"]');
console.log(' Code to redeem game:', code); console.log(' Code to redeem game:', code);
if (store == 'legacy games') { // may be different URL like https://legacygames.com/primeday/puzzleoftheyear/ if (store == 'legacy games') { // may be different URL like https://legacygames.com/primeday/puzzleoftheyear/
redeem[store] = await (await page.$('li:has-text("Click here") a')).getAttribute('href'); redeem[store] = await (await page.$('li:has-text("Click here") a')).getAttribute('href');
} }
console.log(' URL to redeem game:', redeem[store]); console.log(' URL to redeem game:', redeem[store]);
db.data[user][title].code = code;
notify_game.status = `<a href="${redeem[store]}">redeem</a> ${code} on ${store}`;
} else {
notify_game.status = `claimed on ${store}`;
} }
db.data[user][title] ||= { title, time: datetime(), store, code, url: page.url() };
// save screenshot of potential code just in case // save screenshot of potential code just in case
const p = path.resolve(dirs.screenshots, 'prime-gaming', 'external', `${filenamify(title)}.png`); const p = path.resolve(dirs.screenshots, 'prime-gaming', 'external', `${filenamify(title)}.png`);
await page.screenshot({ path: p, fullPage: true }); await page.screenshot({ path: p, fullPage: true });
@ -163,7 +173,13 @@ try {
await page.locator(games_sel).screenshot({ path: p }); await page.locator(games_sel).screenshot({ path: p });
} catch (error) { } catch (error) {
console.error(error); // .toString()? console.error(error); // .toString()?
if (error.message && !error.message.contains('Target closed')) // e.g. when killed by Ctrl-C
notify(`prime-gaming failed: ${error.message}`);
} finally { } finally {
await db.write(); // write out json db await db.write(); // write out json db
if (notify_games.length) { // list should only include claimed games
const list = notify_games.map(g => `- <a href="${g.url}">${g.title}</a> (${g.status})<br>`);
notify(`prime-gaming:<br>${list}`);
}
} }
await context.close(); await context.close();