diff --git a/src/teampulse/resolver.py b/src/teampulse/resolver.py index dced5db..5811caf 100644 --- a/src/teampulse/resolver.py +++ b/src/teampulse/resolver.py @@ -106,53 +106,52 @@ class Resolver: print(f" '{display_name}' via '{strategy}' geklickt — warte auf Dialog...") + print(f" Warte auf E-Mail-Adresse im Dialog (bis 30s)...") try: - # The dialog can take several seconds to fully load — wait up to 15s - self._page.wait_for_selector(".lpc_ip_root_class", timeout=15_000) + # Wait directly for an email address to appear in the lpc-card light DOM. + # This covers both slow dialog opening AND slow content loading. + self._page.wait_for_function( + r"""() => { + const card = document.querySelector('.lpc_ip_root_class lpc-card'); + if (!card) return false; + const EMAIL_RE = /[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/; + if (EMAIL_RE.test(card.textContent)) return true; + if (card.shadowRoot && EMAIL_RE.test(card.shadowRoot.textContent)) return true; + return false; + }""", + timeout=30_000, + ) except Exception: - print(f" Profil-Dialog für '{display_name}' erscheint nicht (Timeout).") + card_text = self._page.evaluate("""() => { + const card = document.querySelector('.lpc_ip_root_class lpc-card'); + if (!card) return '(kein lpc-card)'; + return card.textContent.trim().substring(0, 200); + }""") or "(leer)" + print(f" Profil-Dialog Timeout — Light-DOM-Inhalt: {card_text!r}") self._page.keyboard.press("Escape") return None - # Wait for slotted content to load inside the lpc-card - time.sleep(2) - try: email = self._page.evaluate(r"""() => { - const lpcCard = document.querySelector('.lpc_ip_root_class lpc-card'); - if (!lpcCard) return null; - const EMAIL_RE = /[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/; - - // 1. Slotted content = light DOM children of lpc-card (inserted into ) - const lightLink = lpcCard.querySelector('a[href*="mailto:"]'); + const card = document.querySelector('.lpc_ip_root_class lpc-card'); + if (!card) return null; + // Light DOM (slotted content) + const lightLink = card.querySelector('a[href*="mailto:"]'); if (lightLink) return lightLink.href.replace('mailto:', '').trim(); - - const lightMatch = lpcCard.textContent.match(EMAIL_RE); + const lightMatch = card.textContent.match(EMAIL_RE); if (lightMatch) return lightMatch[0]; - - // 2. Shadow root of lpc-card - if (lpcCard.shadowRoot) { - const shadowLink = lpcCard.shadowRoot.querySelector('a[href*="mailto:"]'); - if (shadowLink) return shadowLink.href.replace('mailto:', '').trim(); - - const shadowMatch = lpcCard.shadowRoot.textContent.match(EMAIL_RE); + // Shadow root + if (card.shadowRoot) { + const shadowMatch = card.shadowRoot.textContent.match(EMAIL_RE); if (shadowMatch) return shadowMatch[0]; } - - // 3. Diagnostic: return light DOM text for inspection - return '__DEBUG__' + lpcCard.textContent.trim().substring(0, 300); + return null; }""") - - if email and email.startswith('__DEBUG__'): - print(f" Dialog offen, E-Mail nicht gefunden. Inhalt: {email[9:200]!r}") - email = None - self._page.keyboard.press("Escape") time.sleep(0.3) return email or None - except Exception as e: - print(f" Fehler beim Lesen des Profil-Dialogs: {e}") + print(f" Fehler beim Lesen: {e}") self._page.keyboard.press("Escape") return None