Clean up Sonar issues and lint warnings
Some checks failed
build-and-push / lint (push) Failing after 5s
build-and-push / sonar (push) Has been skipped
build-and-push / docker (push) Has been skipped

This commit is contained in:
nocci 2025-12-30 16:45:17 +00:00
parent b9aa6e0073
commit 7ffc454e47
6 changed files with 124 additions and 89 deletions

View file

@ -92,7 +92,11 @@ try {
'[data-a-target="user-dropdown-first-name-text"]',
'[data-testid="user-dropdown-first-name-text"]',
].map(s => page.waitForSelector(s)));
page.click('[aria-label="Cookies usage disclaimer banner"] button:has-text("Accept Cookies")').catch(() => { }); // to not waste screen space when non-headless; could be flaky
try {
await page.click('[aria-label="Cookies usage disclaimer banner"] button:has-text("Accept Cookies")'); // to not waste screen space when non-headless; could be flaky
} catch {
// ignore if banner not present
}
while (await page.locator('button:has-text("Sign in"), button:has-text("Anmelden")').count() > 0) {
console.error('Not signed in anymore.');
await page.click('button:has-text("Sign in")');
@ -119,7 +123,11 @@ try {
} catch {
// navigation ok
}
handleMFA(page).catch(() => {});
try {
await handleMFA(page);
} catch {
// ignore MFA watcher errors
}
} else {
console.log('Waiting for you to login in the browser.');
await notify('prime-gaming: no longer signed in and not enough options set for automatic login.');
@ -297,7 +305,6 @@ try {
return [p, isNew];
};
const skipBasedOnTime = async url => {
// console.log(' Checking time left for game:', url);
const [p, isNew] = await sameOrNewPage(url);
const dueDateLoc = p.locator('.availability-date .tw-bold, [data-testid="availability-end-date"], [data-test-selector="availability-end-date"]');
if (!await dueDateLoc.count()) {
@ -321,7 +328,10 @@ try {
console.log('Current free game:', chalk.blue(title));
if (cfg.pg_timeLeft && url && await skipBasedOnTime(url)) continue;
if (cfg.dryrun) continue;
if (cfg.interactive && !await confirm()) continue;
if (cfg.interactive) {
const confirmed = await confirm();
if (!confirmed) continue;
}
await card.handle.locator('.tw-button:has-text("Claim"), .tw-button:has-text("Get"), button:has-text("Claim"), button:has-text("Get")').first().click();
db.data[user][title] ||= { title, time: datetime(), url, store: 'internal' };
notify_games.push({ title, status: 'claimed', url });
@ -336,8 +346,6 @@ try {
if (!url) continue;
external_info.push({ title, url });
}
// external_info = [ { title: 'Fallout 76 (XBOX)', url: 'https://gaming.amazon.com/fallout-76-xbox-fgwp/dp/amzn1.pg.item.9fe17d7b-b6c2-4f58-b494-cc4e79528d0b?ingress=amzn&ref_=SM_Fallout76XBOX_S01_FGWP_CRWN' } ];
const clickCTA = async p => {
const candidates = [
p.locator('button[data-a-target="buy-box_call-to-action"]').first(),
@ -353,14 +361,14 @@ try {
if (await c.count()) {
try {
await c.waitFor({ state: 'visible', timeout: 5000 });
if (!await c.isEnabled()) {
const enabled = await c.isEnabled();
if (enabled) await c.click();
else {
await c.evaluate(el => {
el.disabled = false;
el.removeAttribute('disabled');
el.click();
});
} else {
await c.click();
}
return true;
} catch {
@ -442,7 +450,10 @@ try {
}
if (cfg.pg_timeLeft && await skipBasedOnTime(url)) continue;
if (cfg.dryrun) continue;
if (cfg.interactive && !await confirm()) continue;
if (cfg.interactive) {
const confirmed = await confirm();
if (!confirmed) continue;
}
await clickCTA(page);
await Promise.any([
page.waitForSelector('.thank-you-title:has-text("Success")', { timeout: cfg.timeout }).catch(() => {}),
@ -499,13 +510,9 @@ try {
const page2 = await context.newPage();
await page2.goto(redeem[store], { waitUntil: 'domcontentloaded' });
if (store == 'gog.com') {
// await page.goto(`https://redeem.gog.com/v1/bonusCodes/${code}`); // {"reason":"Invalid or no captcha"}
await page2.fill('#codeInput', code);
// wait for responses before clicking on Continue and then Redeem
// first there are requests with OPTIONS and GET to https://redeem.gog.com/v1/bonusCodes/XYZ?language=de-DE
const r1 = page2.waitForResponse(r => r.request().method() == 'GET' && r.url().startsWith('https://redeem.gog.com/'));
await page2.click('[type="submit"]'); // click Continue
// console.log(await page2.locator('.warning-message').innerText()); // does not exist if there is no warning
const r1t = await (await r1).text();
const reason = JSON.parse(r1t).reason;
// {"reason":"Invalid or no captcha"}
@ -520,14 +527,12 @@ try {
} else if (reason == 'code_not_found') {
redeem_action = 'redeem (not found)';
console.error(' Code was not found!');
} else { // unknown state; keep info log for later analysis
redeem_action = 'redeemed?';
// console.log(' Redeemed successfully? Please report your Responses (if new) in https://github.com/vogler/free-games-claimer/issues/5');
console.debug(` Response 1: ${r1t}`);
// then after the click on Redeem there is a POST request which should return {} if claimed successfully
const r2 = page2.waitForResponse(r => r.request().method() == 'POST' && r.url().startsWith('https://redeem.gog.com/'));
await page2.click('[type="submit"]'); // click Redeem
const r2t = await (await r2).text();
} else { // unknown state; keep info log for later analysis
redeem_action = 'redeemed?';
console.debug(` Response 1: ${r1t}`);
const r2 = page2.waitForResponse(r => r.request().method() == 'POST' && r.url().startsWith('https://redeem.gog.com/'));
await page2.click('[type="submit"]'); // click Redeem
const r2t = await (await r2).text();
const reason2 = JSON.parse(r2t).reason;
if (r2t == '{}') {
redeem_action = 'redeemed';
@ -543,7 +548,6 @@ try {
}
} else if (store == 'microsoft store' || store == 'xbox') {
console.error(` Redeem on ${store} is experimental!`);
// await page2.pause();
if (page2.url().startsWith('https://login.')) {
console.error(' Not logged in! Please redeem the code above manually. You can now login in the browser for next time. Waiting for 60s.');
await page2.waitForTimeout(60 * 1000);
@ -554,9 +558,7 @@ try {
await input.waitFor();
await input.fill(code);
const r = page2.waitForResponse(r => r.url().startsWith('https://cart.production.store-web.dynamics.com/v1.0/Redeem/PrepareRedeem'));
// console.log(await page2.locator('.redeem_code_error').innerText());
const rt = await (await r).text();
// {"code":"NotFound","data":[],"details":[],"innererror":{"code":"TokenNotFound",...
const j = JSON.parse(rt);
const reason = j?.events?.cart.length && j.events.cart[0]?.data?.reason;
if (reason == 'TokenNotFound') {
@ -582,14 +584,12 @@ try {
}
}
} else if (store == 'legacy games') {
// await page2.pause();
await page2.fill('[name=coupon_code]', code);
await page2.fill('[name=email]', cfg.lg_email);
await page2.fill('[name=email_validate]', cfg.lg_email);
await page2.uncheck('[name=newsletter_sub]');
await page2.click('[type="submit"]');
try {
// await page2.waitForResponse(r => r.url().startsWith('https://promo.legacygames.com/promotion-processing/order-management.php')); // status code 302
await page2.waitForSelector('h2:has-text("Thanks for redeeming")');
redeem_action = 'redeemed';
db.data[user][title].status = 'claimed and redeemed';
@ -609,15 +609,16 @@ try {
} else {
notify_game.status = `claimed on ${store}`;
db.data[user][title].status = 'claimed';
}
// save screenshot of potential code just in case
await page.screenshot({ path: screenshot('external', `${filenamify(title)}.png`), fullPage: true });
// console.info(' Saved a screenshot of page to', p);
}
// await page.pause();
await page.screenshot({ path: screenshot('external', `${filenamify(title)}.png`), fullPage: true });
}
}
await page.goto(URL_CLAIM, { waitUntil: 'domcontentloaded' });
page.click('button[data-type="Game"]').catch(() => {});
try {
await page.click('button[data-type="Game"]');
} catch {
// ignore if filter already selected
}
if (notify_games.length && games) { // make screenshot of all games if something was claimed and list exists
const p = screenshot(`${filenamify(datetime())}.png`);
@ -663,15 +664,28 @@ try {
await page.goto(url, { waitUntil: 'domcontentloaded' });
// most games have a button 'Get in-game content'
// epic-games: Fall Guys: Claim -> Continue -> Go to Epic Games (despite account linked and logged into epic-games) -> not tied to account but via some cookie?
await Promise.any([page.click('.tw-button:has-text("Get in-game content")'), page.click('.tw-button:has-text("Claim your gift")'), page.click('.tw-button:has-text("Claim")').then(() => page.click('button:has-text("Continue")'))]);
page.click('button:has-text("Continue")').catch(() => { });
const claimOptions = [
page.click('.tw-button:has-text("Get in-game content")'),
page.click('.tw-button:has-text("Claim your gift")'),
(async () => {
await page.click('.tw-button:has-text("Claim")');
await page.click('button:has-text("Continue")').catch(() => {});
})(),
];
await Promise.any(claimOptions);
try {
await page.click('button:has-text("Continue")');
} catch {
// continue button not always present
}
const linkAccountButton = page.locator('[data-a-target="LinkAccountButton"]');
let unlinked_store;
if (await linkAccountButton.count()) {
unlinked_store = await linkAccountButton.first().getAttribute('aria-label');
console.debug(' LinkAccountButton label:', unlinked_store);
const match = unlinked_store.match(/Link (.*) account/);
if (match && match.length == 2) unlinked_store = match[1];
const match = unlinked_store?.match(/Link (.*) account/);
const extracted = match?.[1];
if (extracted) unlinked_store = extracted;
} else if (await page.locator('text=Link game account').count()) { // epic-games only?
console.error(' Missing account linking (epic-games specific button?):', await page.locator('button[data-a-target="gms-cta"]').innerText()); // track account-linking UI drift
unlinked_store = 'epic-games';
@ -685,9 +699,7 @@ try {
console.log(' Code to redeem game:', chalk.blue(code));
db.data[user][title].code = code;
db.data[user][title].status = 'claimed';
// notify_game.status = `<a href="${redeem[store]}">${redeem_action}</a> ${code} on ${store}`;
}
// await page.pause();
} catch (error) {
console.error(error);
} finally {