diff --git a/src/bot/joinProcedure.ts b/src/bot/joinProcedure.ts index 28f29ec..a9ea7c0 100644 --- a/src/bot/joinProcedure.ts +++ b/src/bot/joinProcedure.ts @@ -15,12 +15,14 @@ export class JoinProcedure { private _logger: Logger; private _botName: string; private _isAuthenticated: boolean; + private _meetingUrl: string; - constructor(page: Page, logger: Logger, botName: string, isAuthenticated: boolean = false) { + constructor(page: Page, logger: Logger, botName: string, isAuthenticated: boolean = false, meetingUrl: string = '') { this._page = page; this._logger = logger; this._botName = botName; this._isAuthenticated = isAuthenticated; + this._meetingUrl = meetingUrl; } /** @@ -175,7 +177,47 @@ export class JoinProcedure { } } - this._logger.warn('Could not confirm authenticated pre-join page after all retries. Proceeding anyway...'); + // Fallback: The automatic redirect to /v2/ did not happen (common in headless browsers). + // Manually navigate to the /v2/ authenticated pre-join URL with auth cookies. + // Format: https://teams.microsoft.com/v2/?meetingjoin=true#/meet/{meetingId}?p={passcode} + if (this._meetingUrl) { + const v2Url = this._buildV2MeetingUrl(this._meetingUrl); + this._logger.info(`Redirect to /v2/ did not happen. Navigating manually to: ${v2Url}`); + await this._page.goto(v2Url, { waitUntil: 'domcontentloaded', timeout: 30000 }); + + // Wait for the /v2/ page to load and check again + for (let attempt = 1; attempt <= 3; attempt++) { + await this._page.waitForTimeout(5000); + const hasNameInput = await this._page.$('input[placeholder="Type your name"]'); + const hasJoinButton = await this._page.$('#prejoin-join-button, button[data-tid="prejoin-join-button"], button:has-text("Join now")'); + const url = this._page.url(); + + if (hasJoinButton && !hasNameInput) { + this._logger.info(`Authenticated pre-join page confirmed after manual nav (attempt ${attempt}/3). URL: ${url.substring(0, 100)}`); + return; + } + + this._logger.info(`After manual nav (attempt ${attempt}/3): hasJoin=${!!hasJoinButton}, hasName=${!!hasNameInput}. URL: ${url.substring(0, 100)}`); + } + } + + this._logger.warn('Could not confirm authenticated pre-join page. Proceeding anyway...'); + } + + /** + * Build the authenticated /v2/ meeting URL from the original meeting URL. + * Input: https://teams.microsoft.com/meet/36438888781520?p=5fGqrujxzewPFjJacW + * Output: https://teams.microsoft.com/v2/?meetingjoin=true#/meet/36438888781520?p=5fGqrujxzewPFjJacW + */ + private _buildV2MeetingUrl(meetingUrl: string): string { + try { + const url = new URL(meetingUrl); + const pathAndQuery = url.pathname + url.search; + return `https://teams.microsoft.com/v2/?meetingjoin=true#${pathAndQuery}`; + } catch { + this._logger.warn(`Could not parse meeting URL: ${meetingUrl}`); + return `https://teams.microsoft.com/v2/?meetingjoin=true`; + } } /** diff --git a/src/bot/orchestrator.ts b/src/bot/orchestrator.ts index d2225fb..7a4f8f7 100644 --- a/src/bot/orchestrator.ts +++ b/src/bot/orchestrator.ts @@ -133,8 +133,8 @@ export class BotOrchestrator { // Launch browser await this._launchBrowser(); - // Update JoinProcedure with correct auth state - this._joinProcedure = new JoinProcedure(this._page!, this._logger, this._botName, authenticate); + // Update JoinProcedure with correct auth state and meeting URL + this._joinProcedure = new JoinProcedure(this._page!, this._logger, this._botName, authenticate, this._meetingUrl); this._setState('navigating');