From 518aa74dc47485ba7b625fe302f0b32e0b7f1915 Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Sun, 17 May 2026 18:07:57 +0200 Subject: [PATCH] fix: extract email after label text, 3s wait, recursive shadow DOM search --- src/teampulse/resolver.py | 46 ++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/teampulse/resolver.py b/src/teampulse/resolver.py index 38e9cd3..e0f186d 100644 --- a/src/teampulse/resolver.py +++ b/src/teampulse/resolver.py @@ -106,27 +106,43 @@ class Resolver: print(f" '{display_name}' via '{strategy}' geklickt — warte auf Dialog...") - # Do NOT poll with wait_for_selector/wait_for_function — - # Playwright's JS polling blocks Teams' async loading of the dialog. - # Simply wait for the dialog to load without interference. - time.sleep(5) + # Do NOT poll — Playwright's JS polling blocks Teams' async dialog loading. + time.sleep(3) try: email = self._page.evaluate(r"""() => { - const EMAIL_RE = /[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/; const card = document.querySelector('.lpc_ip_root_class lpc-card'); if (!card) return '__NO_CARD__'; - // Light DOM (slotted content inserted into elements) - const lightLink = card.querySelector('a[href*="mailto:"]'); - if (lightLink) return lightLink.href.replace('mailto:', '').trim(); - const lightMatch = card.textContent.match(EMAIL_RE); - if (lightMatch) return lightMatch[0]; - // Shadow root fallback - if (card.shadowRoot) { - const shadowMatch = card.shadowRoot.textContent.match(EMAIL_RE); - if (shadowMatch) return shadowMatch[0]; + + // 1. mailto link (most reliable — recurses into nested shadow DOMs) + function findMailto(root) { + const link = root.querySelector('a[href*="mailto:"]'); + if (link) return link.href.replace('mailto:', '').trim(); + for (const el of root.querySelectorAll('*')) { + if (el.shadowRoot) { + const found = findMailto(el.shadowRoot); + if (found) return found; + } + } + return null; } - return '__NO_EMAIL__' + card.textContent.trim().substring(0, 200); + const linked = findMailto(card); + if (linked) return linked; + + // 2. Extract email from text after common label patterns + // Teams dialog text is concatenated without spaces, e.g.: + // "SieKontaktinformationenE-Mailanja@example.com" + const text = card.textContent; + for (const label of ['E-Mail', 'E-mail', 'Email', 'email', 'mail', 'Mail']) { + const idx = text.indexOf(label); + if (idx !== -1) { + const after = text.substring(idx + label.length); + const m = after.match(/^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/); + if (m) return m[0]; + } + } + + return '__NO_EMAIL__' + text.trim().substring(0, 200); }""") if not email or email == '__NO_CARD__':