feat: Add conclusion webhook support for final summary notifications (#355)

- Updated README.md to include new configuration options for conclusion webhook.
- Enhanced BrowserFunc.ts with improved error handling during page reloads.
- Implemented conclusionWebhook configuration in config.json.
- Refactored Login.ts to use Playwright types and improved passkey handling.
- Added safeClick method in SearchOnBing.ts to handle click timeouts and overlays.
- Introduced account summary collection in index.ts for reporting.
- Created ConclusionWebhook.ts to send structured summaries to a dedicated webhook.
- Updated TypeScript definitions for better type safety across the project.
This commit is contained in:
Light
2025-09-14 08:29:09 +02:00
committed by GitHub
parent 2e80266ad1
commit b66114d4dd
15 changed files with 637 additions and 91 deletions

View File

@@ -30,7 +30,7 @@ export class Quiz extends Workers {
for (let i = 0; i < quizData.numberOfOptions; i++) {
const answerSelector = await page.waitForSelector(`#rqAnswerOption${i}`, { state: 'visible', timeout: 10000 })
const answerAttribute = await answerSelector?.evaluate(el => el.getAttribute('iscorrectoption'))
const answerAttribute = await answerSelector?.evaluate((el: any) => el.getAttribute('iscorrectoption'))
if (answerAttribute && answerAttribute.toLowerCase() === 'true') {
answers.push(`#rqAnswerOption${i}`)
@@ -60,7 +60,7 @@ export class Quiz extends Workers {
for (let i = 0; i < quizData.numberOfOptions; i++) {
const answerSelector = await page.waitForSelector(`#rqAnswerOption${i}`, { state: 'visible', timeout: 10000 })
const dataOption = await answerSelector?.evaluate(el => el.getAttribute('data-option'))
const dataOption = await answerSelector?.evaluate((el: any) => el.getAttribute('data-option'))
if (dataOption === correctOption) {
// Click the answer on page

View File

@@ -295,7 +295,7 @@ export class Search extends Workers {
const totalHeight = await page.evaluate(() => document.body.scrollHeight)
const randomScrollPosition = Math.floor(Math.random() * (totalHeight - viewportHeight))
await page.evaluate((scrollPos) => {
await page.evaluate((scrollPos: number) => {
window.scrollTo(0, scrollPos)
}, randomScrollPosition)

View File

@@ -1,4 +1,4 @@
import { Page } from 'rebrowser-playwright'
import type { Page } from 'playwright'
import * as fs from 'fs'
import path from 'path'
@@ -21,7 +21,7 @@ export class SearchOnBing extends Workers {
const searchBar = '#sb_form_q'
await page.waitForSelector(searchBar, { state: 'visible', timeout: 10000 })
await page.click(searchBar)
await this.safeClick(page, searchBar)
await this.bot.utils.wait(500)
await page.keyboard.type(query)
await page.keyboard.press('Enter')
@@ -36,6 +36,22 @@ export class SearchOnBing extends Workers {
}
}
private async safeClick(page: Page, selector: string) {
try {
await page.click(selector, { timeout: 5000 })
} catch (e: any) {
const msg = (e?.message || '')
if (/Timeout.*click/i.test(msg) || /intercepts pointer events/i.test(msg)) {
// Try to dismiss overlays then retry once
await this.bot.browser.utils.tryDismissAllMessages(page)
await this.bot.utils.wait(500)
await page.click(selector, { timeout: 5000 })
} else {
throw e
}
}
}
private async getSearchQuery(title: string): Promise<string> {
interface Queries {
title: string;