// Investor RPG — HyRead 閱讀器內容擷取 const API_HOST = "http://localhost:3000"; function isReaderPage() { return /\/reader\//.test(window.location.pathname) || /reader\.html/.test(window.location.href) || document.querySelector(".hyread-reader") || document.querySelector("#readerContainer") || document.querySelector("[class*='reader']"); } function getBookTitle() { const el = document.querySelector(".book-title") || document.querySelector("h1") || document.querySelector("meta[property='og:title']") || document.querySelector("title"); return el?.textContent?.trim() || el?.getAttribute("content") || "HyRead 書籍"; } function extractPageContent() { const contentSelectors = [ "#pageContent", ".page-content", ".reader-content", "#contentArea", ".content-area", "#textLayer", "section.page", ".book-page", "[class*='page-text']", "#iframeContent", "article", ]; for (const sel of contentSelectors) { const el = document.querySelector(sel); if (el && el.textContent.trim().length > 50) { return { text: el.textContent.trim(), html: el.innerHTML, }; } } const iframes = document.querySelectorAll("iframe"); for (const iframe of iframes) { try { const doc = iframe.contentDocument || iframe.contentWindow?.document; if (doc && doc.body.textContent.trim().length > 50) { return { text: doc.body.textContent.trim(), html: doc.body.innerHTML, }; } } catch {} } const mainText = document.body.innerText?.trim() || ""; return { text: mainText, html: document.body.innerHTML, }; } function getAllPageContent() { const allTexts = []; const allHtmls = []; const content = extractPageContent(); if (content.text.length > 50) { allTexts.push(content.text); allHtmls.push(content.html); } return { text: allTexts.join("\n\n---\n\n"), html: allHtmls.join("\n"), pageCount: allTexts.length, }; } async function captureBook() { const title = getBookTitle(); const content = getAllPageContent(); if (content.text.length < 50) { throw new Error("無法擷取到足夠的內容,請確認閱讀器已開啟"); } const payload = { kind: "hyread", title, url: window.location.href, html: content.html, metadata: { title, url: window.location.href, pageCount: content.pageCount, textLength: content.text.length, }, }; const res = await fetch(`${API_HOST}/api/content/capture`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.message || `伺服器回應 ${res.status}`); } return await res.json(); } function injectCaptureButton() { if (document.querySelector("#irpg-capture-btn")) return; if (!isReaderPage()) return; const btn = document.createElement("button"); btn.id = "irpg-capture-btn"; btn.textContent = "📖 擷取到 RPG"; btn.style.cssText = ` position: fixed; top: 12px; right: 12px; z-index: 99999; background: #2a6c3b; color: #fff; border: none; border-radius: 8px; padding: 8px 16px; font-size: 14px; cursor: pointer; font-weight: 500; box-shadow: 0 2px 8px rgba(0,0,0,.3); transition: background .15s; `; btn.onmouseenter = () => btn.style.background = "#1e7e34"; btn.onmouseleave = () => btn.style.background = "#2a6c3b"; btn.onclick = async () => { btn.textContent = "擷取中..."; btn.disabled = true; try { const result = await captureBook(); btn.textContent = `✓ ${result.count || "已送出"}`; btn.style.background = "#1e7e34"; setTimeout(() => { btn.remove(); }, 3000); } catch (err) { btn.textContent = `✕ ${err.message.slice(0, 25)}`; btn.style.background = "#a13a3a"; setTimeout(() => { btn.textContent = "📖 擷取到 RPG"; btn.style.background = "#2a6c3b"; btn.disabled = false; }, 3000); } }; document.body.appendChild(btn); } setTimeout(injectCaptureButton, 2000); let lastHref = window.location.href; setInterval(() => { if (window.location.href !== lastHref) { lastHref = window.location.href; document.querySelector("#irpg-capture-btn")?.remove(); setTimeout(injectCaptureButton, 1500); } }, 1500);