// In-page DOM snapshot. Kept as plain JavaScript (not TS) so no bundler helper (`__name`) leaks into the page. // Evaluated by PageSummarizer.ts as `(SOURCE)(MAX)`; must remain a single function expression. (MAX) => { const clean = (s) => (s ?? "").replace(/\s+/g, " ").trim(); const vh = window.innerHeight; const regionOf = (node) => { let el = node; let hops = 0; while (el && hops++ < 30) { const role = el.getAttribute("role") ?? ""; const tag = el.tagName.toLowerCase(); if (role === "dialog" || el.getAttribute("aria-modal") === "true") return "dialog"; if (tag === "ytd-comments" || /comment/i.test(el.id) || role === "comment") return "comments"; if (role === "feed") return "feed"; if (role === "main" || tag === "main" || el.id === "primary" || el.id === "contents" || el.id === "main-content") return "main"; if (role === "navigation" || tag === "nav" || el.id === "guide") return "navigation"; if (role === "complementary" || tag === "aside" || el.id === "secondary" || el.id === "related") return "sidebar"; if (tag === "header" || role === "banner" || el.id === "masthead") return "header"; el = el.parentElement; } return "unknown"; }; const cssPath = (el) => { const href = el.getAttribute("href"); const tag = el.tagName.toLowerCase(); if (href) return `${tag}[href="${href.replace(/"/g, '\\"')}"]`; const aria = el.getAttribute("aria-label"); if (aria) return `${tag}[aria-label="${aria.replace(/"/g, '\\"').slice(0, 80)}"]`; if (el.id) return `#${CSS.escape(el.id)}`; const parts = []; let cur = el; let hops = 0; while (cur && hops++ < 6 && cur !== document.body) { const p = cur.parentElement; const idx = p ? Array.from(p.children).indexOf(cur) + 1 : 1; parts.unshift(`${cur.tagName.toLowerCase()}:nth-child(${idx})`); cur = p; } return parts.join(">"); }; const isVisible = (el) => { const r = el.getBoundingClientRect(); const st = getComputedStyle(el); return r.width > 0 && r.height > 0 && st.visibility !== "hidden" && st.display !== "none"; }; const cardMeta = (el) => { let card = el; let hops = 0; const isCard = (n) => n.tagName === "ARTICLE" || n.getAttribute("role") === "article" || n.tagName === "LI" || /-(renderer|item|lockup|post)$|^shreddit-post$|view-model$/i.test(n.tagName) || /(^|\s)(card|post|feed-item|lockup)(\s|$)/i.test(typeof n.className === "string" ? n.className : ""); while (card && hops++ < 6 && !isCard(card)) card = card.parentElement; // Only trust a card scope of bounded size; a huge container would bleed another item's numbers into this one. const scope = card && clean(card.textContent).length < 1500 ? card : el; const text = clean(scope.textContent).slice(0, 1200); const out = {}; const dur = text.match(/(?:^|\s)(\d{1,2}:\d{2}(?::\d{2})?)(?=\s|$)/); if (dur) out.duration = dur[1]; const views = text.match(/([\d.,\s]+\s?[kKmMbB]?)\s*(vues|views|visionnements|upvotes|points|votes|likes|j'aime)/i); if (views) out.views = views[0]; const comments = text.match(/([\d.,\s]+\s?[kKmMbB]?)\s*(comment|commentaire|repl|répon)/i); if (comments) out.comments = comments[0]; const ago = text.match(/(il y a\s+[\w\s]+?|\d+\s+(seconds?|minutes?|hours?|days?|weeks?|months?|years?|h|min|j|sem|mois|ans?)\s+ago|\b\d+\s*(h|min|j|d|w|mo|y)\b)/i); if (ago) out.published = ago[0]; const authorLink = scope.querySelector('a[href*="/@"], a[href^="/user/"], a[href^="/u/"], a[href*="/channel/"], a[href^="/c/"], a[href*="/r/"]'); if (authorLink && authorLink !== el) out.author = clean(authorLink.textContent) || (authorLink.getAttribute("href") ?? ""); return out; }; const seen = new Set(); const candidates = []; let index = 0; const push = (c) => { const key = c.kind + "|" + (c.href ?? "") + "|" + c.text.slice(0, 80); if (seen.has(key)) return; seen.add(key); candidates.push({ ...c, index: index++ }); }; for (const a of Array.from(document.querySelectorAll("a[href]"))) { if (candidates.length >= MAX) break; if (!isVisible(a)) continue; const href = a.href; if (!href || href.startsWith("javascript:")) continue; const img = a.querySelector("img"); const text = clean(a.textContent) || clean(a.getAttribute("aria-label")) || clean(a.getAttribute("title")) || clean(img ? img.alt : ""); if (!text && !/watch|shorts|comments|status|reel|video|\/p\//.test(href)) continue; const r = a.getBoundingClientRect(); push({ kind: "link", href, text: text.slice(0, 200), aria_label: clean(a.getAttribute("aria-label")) || undefined, role: a.getAttribute("role") ?? undefined, region: regionOf(a), visible: r.top < vh && r.bottom > 0, top: Math.round(r.top + window.scrollY), meta: cardMeta(a), locator_hint: cssPath(a) }); } for (const art of Array.from(document.querySelectorAll("article,[role=article],shreddit-post,ytd-rich-item-renderer,ytd-video-renderer,ytd-compact-video-renderer,ytd-reel-item-renderer,ytd-comment-thread-renderer"))) { if (candidates.length >= MAX) break; if (!isVisible(art)) continue; const r = art.getBoundingClientRect(); const link = art.querySelector("a[href]"); push({ kind: "article", href: link ? link.href : undefined, text: clean(art.textContent).slice(0, 300), role: art.getAttribute("role") ?? art.tagName.toLowerCase(), region: regionOf(art), visible: r.top < vh && r.bottom > 0, top: Math.round(r.top + window.scrollY), meta: cardMeta(art), locator_hint: cssPath(link ?? art) }); } for (const h of Array.from(document.querySelectorAll("h1,h2,[role=heading]")).slice(0, 30)) { if (!isVisible(h)) continue; const r = h.getBoundingClientRect(); const text = clean(h.textContent); if (!text) continue; push({ kind: "heading", text: text.slice(0, 200), region: regionOf(h), visible: r.top < vh && r.bottom > 0, top: Math.round(r.top + window.scrollY), locator_hint: cssPath(h) }); } for (const s of Array.from(document.querySelectorAll('input[type=search],input[name*=search i],input[placeholder*=search i],input[placeholder*=recherch i],[role=searchbox],[role=combobox][aria-label*=search i],[role=combobox][aria-label*=recherch i]'))) { if (!isVisible(s)) continue; const r = s.getBoundingClientRect(); push({ kind: "search", text: clean(s.getAttribute("placeholder") ?? s.getAttribute("aria-label")) || "search", region: regionOf(s), visible: r.top < vh, top: Math.round(r.top + window.scrollY), locator_hint: cssPath(s) }); } for (const b of Array.from(document.querySelectorAll("button,[role=button],summary,[aria-expanded]"))) { if (candidates.length >= MAX) break; if (!isVisible(b)) continue; const label = clean(b.getAttribute("aria-label")) || clean(b.textContent); if (!/more|plus|show|afficher|voir|replies|réponses|comments|commentaires|expand|load|charger|read more|lire la suite|\.\.\./i.test(label)) continue; const r = b.getBoundingClientRect(); push({ kind: "button", text: label.slice(0, 120), aria_label: clean(b.getAttribute("aria-label")) || undefined, role: b.getAttribute("role") ?? "button", region: regionOf(b), visible: r.top < vh && r.bottom > 0, top: Math.round(r.top + window.scrollY), locator_hint: cssPath(b) }); } const videos = Array.from(document.querySelectorAll("video")).map((v) => ({ src: v.getAttribute("src") ?? undefined, current_src: v.currentSrc || undefined, duration: Number.isFinite(v.duration) ? v.duration : undefined, width: v.videoWidth, height: v.videoHeight, playing: !v.paused && !v.ended && v.readyState > 2, poster: v.poster || undefined, })); const main = document.querySelector("main,[role=main],#primary,#main-content,#contents") ?? document.body; const landmarks = Array.from(document.querySelectorAll("[role],main,nav,aside,header,footer,form")).map((e) => e.getAttribute("role") ?? e.tagName.toLowerCase()); const h1 = document.querySelector("h1"); return { url: location.href, title: document.title, lang: document.documentElement.lang || undefined, h1: clean(h1 ? h1.textContent : "") || undefined, landmarks: Array.from(new Set(landmarks)).slice(0, 25), candidates, video_elements: videos, text_excerpt: clean(main.textContent).slice(0, 600), scroll: { y: window.scrollY, height: document.documentElement.scrollHeight, viewport: vh }, has_login_form: !!document.querySelector("input[type=password]"), dialog_open: !!document.querySelector("[role=dialog]:not([aria-hidden=true]),[aria-modal=true]"), }; }