File size: 2,503 Bytes
966d483 b25af45 966d483 613c7f2 966d483 613c7f2 966d483 7fd73e2 966d483 7fd73e2 966d483 b25af45 966d483 b25af45 966d483 b25af45 966d483 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | /**
* 定根:text/plain 整页即正文;其余走 Readability(预打标 → clone → data-il-rid 映回),
* 再经 extractRootPatches 手动修补。Readability 失败抛错,不回退启发式。
*/
(() => {
const ATTR = 'data-il-rid';
/**
* 浏览器对 text/plain(.txt / .py raw 等)的原生查看器:整页即正文。
* @param {Document} doc
* @returns {Element | null}
*/
function findPlainTextRoot(doc) {
if (!doc.body) return null;
if (doc.contentType === 'text/plain') return doc.body;
return null;
}
function mark(doc) {
if (!doc.body) return;
let seq = 0;
// body 本身也要打标:Readability 退到合成根时映回 page/body
doc.body.setAttribute(ATTR, String(++seq));
for (const el of doc.body.querySelectorAll('*')) {
el.setAttribute(ATTR, String(++seq));
}
}
function unmark(doc) {
if (!doc.body) return;
doc.body.removeAttribute(ATTR);
for (const el of doc.body.querySelectorAll(`[${ATTR}]`)) {
el.removeAttribute(ATTR);
}
}
/** @param {Element} root @param {Document} doc */
function applyPatches(root, doc) {
const apply = globalThis.IL_applyExtractRootPatches;
if (typeof apply !== 'function') {
throw new Error('IL_applyExtractRootPatches missing — inject extractRootPatches.js first');
}
return apply(root, doc);
}
/**
* @param {Document} doc
* @returns {Element}
*/
function findArticleRoot(doc) {
if (!doc?.body) {
throw new Error('document.body missing');
}
const plain = findPlainTextRoot(doc);
if (plain) return applyPatches(plain, doc);
if (typeof Readability !== 'function') {
throw new Error('Readability missing — inject vendor/Readability.js first');
}
mark(doc);
try {
const clone = doc.cloneNode(true);
const reader = new Readability(clone);
const parsed = reader.parse();
if (!parsed) {
throw new Error('Readability: parse failed');
}
const rid = reader._ilArticleRootRid;
if (rid == null || rid === '') {
throw new Error('Readability: no mappable article root');
}
const root = doc.querySelector(`[${ATTR}="${CSS.escape(String(rid))}"]`);
if (!root) {
throw new Error(`Readability: live root not found (rid=${rid})`);
}
return applyPatches(root, doc);
} finally {
unmark(doc);
}
}
globalThis.IL_findArticleRoot = findArticleRoot;
})();
|