finance-tools/extension/content-hyread.js

162 lines
4.4 KiB
JavaScript
Raw Normal View History

2026-06-22 09:16:20 +00:00
// 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);