import asyncio import logging import re from playwright.async_api import BrowserContext, Page from .base import BaseProvider logger = logging.getLogger(__name__) class TempMailOrgProvider(BaseProvider): def __init__(self, browser_session: BrowserContext): super().__init__(browser_session) self.page: Page | None = None async def _ensure_page(self) -> Page: if self.page is None or self.page.is_closed(): self.page = await self.browser_session.new_page() return self.page async def get_new_email(self) -> str: page = await self._ensure_page() logger.info("[temp-mail.org] Opening mailbox page") await page.goto("https://temp-mail.org", wait_until="domcontentloaded") await page.locator("input#mail, #mail, input[value*='@']").first.wait_for( state="visible", timeout=30000, ) selectors = ["#mail", "input#mail", "input[value*='@']"] end_at = asyncio.get_running_loop().time() + 60 while asyncio.get_running_loop().time() < end_at: await page.bring_to_front() for selector in selectors: try: field = page.locator(selector).first if await field.is_visible(timeout=1000): value = (await field.input_value()).strip() if "@" in value: logger.info( "[temp-mail.org] selector matched: %s -> %s", selector, value, ) return value except Exception: continue try: body = await page.inner_text("body") found = extract_email(body) if found: logger.info("[temp-mail.org] email found by body scan: %s", found) return found except Exception: pass await asyncio.sleep(1) raise RuntimeError("Could not get temp email from temp-mail.org") async def get_latest_message(self, email: str) -> str | None: page = await self._ensure_page() logger.info("[temp-mail.org] Waiting for latest message for %s", email) if page.is_closed(): raise RuntimeError("temp-mail.org tab was closed unexpectedly") await page.bring_to_front() items = page.locator("div.inbox-dataList ul li") # temp-mail updates inbox via websocket; do not refresh/reload page. for attempt in range(30): try: count = await items.count() logger.info("[temp-mail.org] inbox items: %s", count) except Exception: count = 0 if count > 0: for idx in reversed(range(count)): try: item = items.nth(idx) if not await item.is_visible(timeout=1000): continue text = (await item.inner_text()).strip().replace("\n", " ") logger.info("[temp-mail.org] item[%s]: %s", idx, text[:160]) except Exception: continue if text: try: await item.click() logger.info("[temp-mail.org] opened item[%s]", idx) except Exception: pass message_text = text try: content = await page.content() if content and "Your ChatGPT code is" in content: message_text = content except Exception: pass try: await page.go_back( wait_until="domcontentloaded", timeout=5000 ) logger.info("[temp-mail.org] returned back to inbox") except Exception: pass return message_text await asyncio.sleep(2) logger.warning("[temp-mail.org] No messages received within 60 seconds") return None def extract_email(text: str) -> str | None: match = re.search(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}", text) return match.group(0) if match else None