fix: parse meeting ID + passcode separately, fill both fields, click Join meeting
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
8ed183f13c
commit
f7e0c194d5
1 changed files with 151 additions and 26 deletions
|
|
@ -363,37 +363,105 @@ async function _runVariant(
|
||||||
_log('warn', '"Join a meeting" button not found on landing page');
|
_log('warn', '"Join a meeting" button not found on landing page');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the resulting page to FULLY load
|
// Wait for the "Join a meeting" form to FULLY load
|
||||||
_log('info', 'Waiting for resulting page to fully load...');
|
_log('info', 'Waiting for Join a meeting form to load...');
|
||||||
await page.waitForTimeout(5000);
|
await page.waitForTimeout(5000);
|
||||||
try {
|
try {
|
||||||
await page.waitForLoadState('networkidle', { timeout: 20000 });
|
await page.waitForLoadState('networkidle', { timeout: 20000 });
|
||||||
} catch {
|
} catch {
|
||||||
_log('warn', 'networkidle timeout, continuing');
|
_log('warn', 'networkidle timeout, continuing');
|
||||||
}
|
}
|
||||||
await page.waitForTimeout(5000);
|
await page.waitForTimeout(3000);
|
||||||
await _screenshotStep('3 - Nach "Join a meeting"');
|
await _screenshotStep('3 - Join a meeting Formular');
|
||||||
|
|
||||||
// If there's an input for meeting URL, enter it
|
// Parse meeting URL to extract Meeting ID and Passcode
|
||||||
_log('info', 'Looking for meeting URL input...');
|
// URL format: https://teams.microsoft.com/meet/36438888781520?p=5fGqrujxzewPFjJacW
|
||||||
const meetingInputSelectors = [
|
const { meetingId, passcode } = _parseMeetingUrl(meetingUrl);
|
||||||
|
_log('info', `Parsed meeting URL: ID="${meetingId}", Passcode="${passcode ? passcode.substring(0, 5) + '...' : 'none'}"`);
|
||||||
|
|
||||||
|
// Fill Meeting ID field
|
||||||
|
if (meetingId) {
|
||||||
|
_log('info', 'Looking for Meeting ID input...');
|
||||||
|
const idInputSelectors = [
|
||||||
'input[placeholder*="meeting" i]',
|
'input[placeholder*="meeting" i]',
|
||||||
'input[placeholder*="code" i]',
|
'input[placeholder*="Meeting ID" i]',
|
||||||
'input[placeholder*="link" i]',
|
|
||||||
'input[placeholder*="ID" i]',
|
'input[placeholder*="ID" i]',
|
||||||
'input[type="text"]',
|
'input[aria-label*="Meeting ID" i]',
|
||||||
'input[type="url"]',
|
'input[type="text"]:first-of-type',
|
||||||
];
|
];
|
||||||
|
|
||||||
let meetingInputFound = false;
|
let idFilled = false;
|
||||||
for (const selector of meetingInputSelectors) {
|
for (const selector of idInputSelectors) {
|
||||||
try {
|
try {
|
||||||
const input = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
|
const input = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
|
||||||
if (input) {
|
if (input) {
|
||||||
await input.fill(meetingUrl);
|
await input.fill(meetingId);
|
||||||
_log('info', `Entered meeting URL in: ${selector}`);
|
_log('info', `Entered Meeting ID in: ${selector}`);
|
||||||
meetingInputFound = true;
|
idFilled = true;
|
||||||
await page.waitForTimeout(3000);
|
await page.waitForTimeout(1000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Try next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!idFilled) {
|
||||||
|
_log('warn', 'Meeting ID input not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill Passcode field
|
||||||
|
if (passcode) {
|
||||||
|
_log('info', 'Looking for Passcode input...');
|
||||||
|
const passcodeSelectors = [
|
||||||
|
'input[placeholder*="passcode" i]',
|
||||||
|
'input[placeholder*="Passcode" i]',
|
||||||
|
'input[placeholder*="password" i]',
|
||||||
|
'input[aria-label*="passcode" i]',
|
||||||
|
'input[aria-label*="Passcode" i]',
|
||||||
|
];
|
||||||
|
|
||||||
|
let passcodeFilled = false;
|
||||||
|
for (const selector of passcodeSelectors) {
|
||||||
|
try {
|
||||||
|
const input = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
|
||||||
|
if (input) {
|
||||||
|
await input.fill(passcode);
|
||||||
|
_log('info', `Entered Passcode in: ${selector}`);
|
||||||
|
passcodeFilled = true;
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Try next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!passcodeFilled) {
|
||||||
|
_log('warn', 'Passcode input not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _screenshotStep('4 - Meeting-Daten eingegeben');
|
||||||
|
|
||||||
|
// Click "Join meeting" button
|
||||||
|
_log('info', 'Looking for "Join meeting" button...');
|
||||||
|
const joinBtnSelectors = [
|
||||||
|
'button:has-text("Join meeting")',
|
||||||
|
'button:has-text("Besprechung beitreten")',
|
||||||
|
'button:has-text("Join now")',
|
||||||
|
'button:has-text("Jetzt teilnehmen")',
|
||||||
|
'button[data-tid="joinMeetingButton"]',
|
||||||
|
'button[data-tid="join-meeting-button"]',
|
||||||
|
];
|
||||||
|
|
||||||
|
let joinClicked = false;
|
||||||
|
for (const selector of joinBtnSelectors) {
|
||||||
|
try {
|
||||||
|
const btn = await page.waitForSelector(selector, { timeout: 5000, state: 'visible' });
|
||||||
|
if (btn) {
|
||||||
|
await btn.click();
|
||||||
|
_log('info', `Clicked "Join meeting": ${selector}`);
|
||||||
|
joinClicked = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -401,14 +469,38 @@ async function _runVariant(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meetingInputFound) {
|
if (!joinClicked) {
|
||||||
await page.waitForTimeout(5000);
|
_log('warn', '"Join meeting" button not found — logging all visible buttons');
|
||||||
await _screenshotStep('4 - Meeting URL eingegeben');
|
try {
|
||||||
} else {
|
const buttons = await page.evaluate(() => {
|
||||||
_log('warn', 'No meeting URL input field found');
|
const btns = document.querySelectorAll('button');
|
||||||
|
return Array.from(btns).slice(0, 20).map(b => {
|
||||||
|
const text = (b.textContent || '').trim().substring(0, 80);
|
||||||
|
const tid = b.getAttribute('data-tid') || '';
|
||||||
|
const disabled = b.disabled ? ' DISABLED' : '';
|
||||||
|
return `[BUTTON tid="${tid}"${disabled}] ${text}`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
buttons.forEach(b => _log('info', ` ${b}`));
|
||||||
|
} catch {
|
||||||
|
// Ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for resulting page after clicking Join
|
||||||
|
if (joinClicked) {
|
||||||
|
_log('info', 'Waiting for page after Join meeting...');
|
||||||
|
await page.waitForTimeout(5000);
|
||||||
|
try {
|
||||||
|
await page.waitForLoadState('networkidle', { timeout: 30000 });
|
||||||
|
} catch {
|
||||||
|
_log('warn', 'networkidle timeout after Join, continuing');
|
||||||
|
}
|
||||||
|
await page.waitForTimeout(10000);
|
||||||
|
}
|
||||||
|
await _screenshotStep('5 - Nach Join meeting');
|
||||||
|
}
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// FINAL: Log result
|
// FINAL: Log result
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
@ -753,6 +845,39 @@ function _getDeviceSpoofScript(): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// MEETING URL PARSER
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a Teams meeting URL to extract Meeting ID and Passcode.
|
||||||
|
* URL format: https://teams.microsoft.com/meet/36438888781520?p=5fGqrujxzewPFjJacW
|
||||||
|
* Meeting ID: 36438888781520 (from path)
|
||||||
|
* Passcode: 5fGqrujxzewPFjJacW (from ?p= parameter)
|
||||||
|
*/
|
||||||
|
function _parseMeetingUrl(meetingUrl: string): { meetingId: string; passcode: string | null } {
|
||||||
|
try {
|
||||||
|
const parsed = new URL(meetingUrl.trim());
|
||||||
|
|
||||||
|
// Extract meeting ID from path: /meet/36438888781520
|
||||||
|
let meetingId = '';
|
||||||
|
if (parsed.pathname.includes('/meet/')) {
|
||||||
|
meetingId = parsed.pathname.split('/meet/')[1] || '';
|
||||||
|
// Remove trailing slashes
|
||||||
|
meetingId = meetingId.replace(/\/$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract passcode from ?p= parameter
|
||||||
|
const passcode = parsed.searchParams.get('p') || null;
|
||||||
|
|
||||||
|
return { meetingId, passcode };
|
||||||
|
} catch {
|
||||||
|
// If URL parsing fails, try to extract digits as meeting ID
|
||||||
|
const digits = meetingUrl.replace(/\D/g, '');
|
||||||
|
return { meetingId: digits, passcode: null };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// URL RESOLUTION
|
// URL RESOLUTION
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue