feat(myTischtennis): enhance CAPTCHA handling and refactor controller logic

- Added visual state tracking for CAPTCHA elements in MyTischtennisClient to improve interaction reliability.
- Increased timeout for CAPTCHA field population to ensure proper handling during login.
- Refactored MyTischtennisController to utilize myTischtennisProxyService for content rewriting and session management, streamlining the login process.
- Removed deprecated content rewriting logic, enhancing code maintainability and clarity.
This commit is contained in:
Torsten Schulz (local)
2026-03-02 09:05:43 +01:00
parent 12bba26ff1
commit cf8cf17dc7
9 changed files with 933 additions and 800 deletions

View File

@@ -398,6 +398,17 @@ class MyTischtennisClient {
if (await captchaHost.count()) {
try {
await page.waitForTimeout(1200);
const captchaVisualStateBefore = await page.evaluate(() => {
const host = document.querySelector('private-captcha');
const checkbox = host?.shadowRoot?.querySelector('#pc-checkbox');
return {
hostClass: host?.className || null,
hostDataState: host?.getAttribute?.('data-state') || null,
checkboxClass: checkbox?.className || null,
checkboxChecked: !!checkbox?.checked,
checkboxAriaChecked: checkbox?.getAttribute?.('aria-checked') || null
};
});
const interaction = await page.evaluate(() => {
const host = document.querySelector('private-captcha');
const checkbox = host?.shadowRoot?.querySelector('#pc-checkbox');
@@ -416,6 +427,58 @@ class MyTischtennisClient {
});
console.log('[myTischtennisClient.playwright] evaluate interaction result:', interaction);
// Wait for a visual captcha state change in Shadow DOM (not only hidden fields).
try {
await page.waitForFunction((beforeState) => {
const host = document.querySelector('private-captcha');
const checkbox = host?.shadowRoot?.querySelector('#pc-checkbox');
if (!host || !checkbox) return false;
const current = {
hostClass: host.className || '',
hostDataState: host.getAttribute?.('data-state') || '',
checkboxClass: checkbox.className || '',
checkboxChecked: !!checkbox.checked,
checkboxAriaChecked: checkbox.getAttribute?.('aria-checked') || ''
};
const visualChanged =
current.hostClass !== (beforeState?.hostClass || '')
|| current.hostDataState !== (beforeState?.hostDataState || '')
|| current.checkboxClass !== (beforeState?.checkboxClass || '')
|| current.checkboxChecked !== !!beforeState?.checkboxChecked
|| current.checkboxAriaChecked !== (beforeState?.checkboxAriaChecked || '');
const positiveSignals = [
current.hostClass,
current.hostDataState,
current.checkboxClass,
String(current.checkboxAriaChecked)
].join(' ').toLowerCase();
return visualChanged && (
current.checkboxChecked
|| current.checkboxAriaChecked === 'true'
|| /success|solved|verified|checked|active|complete|done/.test(positiveSignals)
);
}, captchaVisualStateBefore, { timeout: 30000 });
const captchaVisualStateAfter = await page.evaluate(() => {
const host = document.querySelector('private-captcha');
const checkbox = host?.shadowRoot?.querySelector('#pc-checkbox');
return {
hostClass: host?.className || null,
hostDataState: host?.getAttribute?.('data-state') || null,
checkboxClass: checkbox?.className || null,
checkboxChecked: !!checkbox?.checked,
checkboxAriaChecked: checkbox?.getAttribute?.('aria-checked') || null
};
});
console.log('[myTischtennisClient.playwright] Captcha visual state changed:', captchaVisualStateAfter);
} catch (_visualWaitErr) {
console.warn('[myTischtennisClient.playwright] Captcha visual state did not change in time');
}
// Wait until hidden captcha fields are populated by site scripts.
try {
await page.waitForFunction(() => {
@@ -424,7 +487,7 @@ class MyTischtennisClient {
const captchaValue = (captchaField && captchaField.value ? captchaField.value.trim() : '');
const clickedValue = (clickedField && clickedField.value ? clickedField.value.toLowerCase() : '');
return captchaValue.length > 80 && (clickedValue === 'true' || clickedValue === '1');
}, { timeout: 15000 });
}, { timeout: 30000 });
const captchaState = await page.evaluate(() => {
const captchaField = document.querySelector('input[name="captcha"]');
const clickedField = document.querySelector('input[name="captcha_clicked"]');