// ==UserScript== // @name 菠萝猫原生阅读自动接续(Via) // @namespace local.boluomao.nativepager // @version 1.8.0 // @description 自动阅读与接续、原位目录、历史进度、手机备份恢复、连读内存控制与广告防护。 // @downloadURL https://paste.brianrianrehan.com/raw/gZRAXhL5P // @match https://www.boluomao1.com/book/* // @match https://www.boluomao1.com/read/* // @match https://www.rrssk.com/* // @run-at document-start // @grant none // @noframes // ==/UserScript== /* 不依赖 GM_*;原生阅读未响应时显示兼容阅读层,不自动处理验证码。 * 与 Via 广告规则配合使用;请停用旧版“菠萝猫纯净连读”脚本。 */ (function () { 'use strict'; if (window.top !== window) return; if (location.hostname === 'www.rrssk.com') { installSearchResultLinks(); return; } if (location.hostname !== 'www.boluomao1.com' || !/^\/(?:book|read)\//.test(location.pathname) || window.__bmNativePagerInstalled) return; window.__bmNativePagerInstalled = true; var origin = location.origin; var searchEntry = new URL('https://www.rrssk.com/boluomao.html'); var searchNavigationUntil = 0; var match = location.pathname.match(/^\/read\/(\d+)\/\d+\.html$/); var bookId = match && match[1]; var state = { source: null, first: null, next: null, pages: [], seen: new Set(), reader: null, content: null, status: null, paper: null, toolbar: null, toolbarHandle: null, tocPanel: null, tocList: null, tocPages: null, tocStatus: null, tocOpen: false, tocPage: 1, tocMax: 1, tocSeq: 0, tocCache: new Map(), tocController: null, progressPanel: null, progressList: null, progressStatus: null, progressOpen: false, progressSeq: 0, progressTimer: null, progressTouched: false, savedProgress: null, pendingResume: null, progressHistory: { furthest: null, recent: [] }, chapterOrders: new Map(), chapterTitles: new Map(), forwardLinks: new Map(), busy: false, blocked: false, readSeq: 0, autoEntryTimer: null, autoEntryDone: false, compactedPages: 0, compacting: false, backupDownloadAnchor: null, backupDownloadUrl: null, error: '', lastRequest: 0, timer: null }; function installSearchResultLinks() { if (window.__bmSearchLinksInstalled) return; window.__bmSearchLinksInstalled = true; window.addEventListener('click', function (event) { if (!event.target || !event.target.closest) return; var card = event.target.closest('.book-card'); if (!card) return; var raw = ''; var handler = card.getAttribute('onclick') || ''; var opened = handler.match(/^\s*window\.open\(\s*(['"])([^'"]*)\1\s*(?:,\s*(['"])_blank\3\s*)?\)\s*;?\s*$/); if (handler && !opened) return; if (opened) raw = opened[2]; else { var link = event.target.closest('a[href]') || card.querySelector('a[href]'); if (link) raw = link.getAttribute('href'); } var searchTarget = currentSearchBook(raw); if (!searchTarget) return; event.preventDefault(); event.stopImmediatePropagation(); location.assign(searchTarget.href); }, true); } function currentSearchBook(value) { try { var wrapper = new URL(value, location.href); var raw = value; if (wrapper.origin === location.origin && wrapper.searchParams.get('action') === 'go') { var encoded = wrapper.searchParams.get('t'); if (!encoded || encoded.length > 2048) return null; raw = atob(encoded); } var logo = document.querySelector('.logo-text'); var boluomaoSource = !!logo && /^菠萝猫$/.test(logo.textContent.trim()); if (/^\/\d+\.html$/.test(raw)) { if (!boluomaoSource) return null; raw = 'https://www.boluomao1.com/book' + raw; } else if (/^\/(?:book|read)\//.test(raw)) { if (!boluomaoSource) return null; raw = 'https://www.boluomao1.com' + raw; } var target = new URL(raw); if (target.protocol !== 'https:' || target.port || target.username || target.password || !/^(?:www\.)?boluomao(?:1)?\.com$/.test(target.hostname) || !/^\/(?:book\/\d+|read\/\d+\/\d+)\.html$/.test(target.pathname)) return null; var valid = true; target.searchParams.forEach(function (item, key) { if (!/^(?:p|cp)$/.test(key) || !/^[1-9]\d*$/.test(item)) valid = false; }); if (!valid) return null; target.hostname = 'www.boluomao1.com'; return target; } catch (_) { return null; } } function intentionalSearchNavigation(value) { try { var target = new URL(value); return Date.now() <= searchNavigationUntil && target.href === searchEntry.href; } catch (_) { return false; } } // 图片在打包时压缩并直接内置。脚本导入手机后,切换背景无需网络或外部文件。 var paperImages = { amber: 'data:image/jpeg;base64,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', sage: 'data:image/jpeg;base64,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' }; var themes = [ { id: 'ivory', label: '米白', bg: '#faf6eb', text: '#333333', bar: 'rgba(250,246,235,.96)' }, { id: 'amber', label: '仿 Alook 暖纸', bg: '#e0c5a2', text: '#333333', bar: 'rgba(224,197,162,.96)', image: paperImages.amber, tint: 'rgba(221,196,165,.8)' }, { id: 'sage', label: '浅绿纸', bg: '#d1efd7', text: '#2e3931', bar: 'rgba(209,239,215,.96)', image: paperImages.sage, tint: 'rgba(209,239,215,.45)' }, { id: 'night', label: '夜间', bg: '#141517', text: '#dededc', bar: 'rgba(20,21,23,.96)' } ]; var themeKey = 'bm-reader-theme-v1'; var currentTheme = 'amber'; try { currentTheme = localStorage.getItem(themeKey) || 'amber'; } catch (_) {} if (!themes.some(function (theme) { return theme.id === currentTheme; })) currentTheme = 'amber'; var toolbarKey = 'bm-reader-toolbar-collapsed-v1'; var toolbarCollapsed = false; try { toolbarCollapsed = localStorage.getItem(toolbarKey) === '1'; } catch (_) {} var tocPageKey = 'bm-reader-catalog-page-' + bookId; var progressKey = 'bm-reader-progress-' + bookId; var historyKey = 'bm-reader-progress-history-' + bookId + '-v1'; var chapterOrderKey = 'bm-reader-chapter-order-' + bookId + '-v1'; var chapterTitleKey = 'bm-reader-chapter-title-' + bookId + '-v1'; var pendingKey = 'bm-reader-pending-resume-' + bookId; try { var savedCp = Number(localStorage.getItem(tocPageKey)); if (savedCp >= 1 && savedCp <= 100 && savedCp % 1 === 0) state.tocPage = savedCp; } catch (_) {} if (bookId) { try { var storedOrders = JSON.parse(localStorage.getItem(chapterOrderKey) || '[]'); if (Array.isArray(storedOrders)) storedOrders.forEach(function (item) { if (Array.isArray(item) && /^\/read\/\d+\/\d+\.html$/.test(item[0]) && Number.isInteger(item[1]) && item[1] > 0 && item[1] <= 100000) { state.chapterOrders.set(item[0], item[1]); } }); } catch (_) {} try { var storedTitles = JSON.parse(localStorage.getItem(chapterTitleKey) || '[]'); if (Array.isArray(storedTitles)) storedTitles.forEach(function (item) { if (Array.isArray(item) && typeof item[0] === 'string' && typeof item[1] === 'string') { state.chapterTitles.set(item[0], cleanChapterTitle(item[1])); } }); } catch (_) {} } try { state.savedProgress = JSON.parse(localStorage.getItem(progressKey) || 'null'); } catch (_) {} if (bookId) loadProgressHistory(); try { state.pendingResume = JSON.parse(sessionStorage.getItem(pendingKey) || 'null'); } catch (_) {} var fontKey = 'bm-reader-font-size-v1'; var fontSize = 22; var fontTouch = { button: null, at: 0 }; try { var savedFont = Number(localStorage.getItem(fontKey)); if (savedFont >= 16 && savedFont <= 34 && savedFont % 1 === 0) fontSize = savedFont; } catch (_) {} function applyFontSize(size) { var anchor = captureFontAnchor(); fontSize = Math.max(16, Math.min(34, size)); try { localStorage.setItem(fontKey, String(fontSize)); } catch (_) {} if (state.content) state.content.style.setProperty('font-size', fontSize + 'px', 'important'); restoreFontAnchor(anchor); if (!state.toolbar) return; var value = state.toolbar.querySelector('[data-bm-font-value]'); if (value) { value.textContent = String(fontSize); value.setAttribute('aria-label', '当前字号 ' + fontSize + ' 像素'); } var buttons = state.toolbar.querySelectorAll('[data-bm-font-step]'); for (var i = 0; i < buttons.length; i++) { var step = Number(buttons[i].getAttribute('data-bm-font-step')); buttons[i].disabled = step < 0 ? fontSize <= 16 : fontSize >= 34; buttons[i].style.setProperty('opacity', buttons[i].disabled ? '.4' : '1', 'important'); } } function captureFontAnchor() { if (!activeReader() || !state.reader.scrollTop) return null; var anchorY = state.reader.getBoundingClientRect().top + Math.min(120, state.reader.clientHeight * .22); var paragraphs = state.content.querySelectorAll('p[data-bm-progress-index]'); for (var i = 0; i < paragraphs.length; i++) { var rect = paragraphs[i].getBoundingClientRect(); if (!(rect.height > 0) || rect.bottom <= anchorY) continue; return { node: paragraphs[i], y: anchorY, ratio: Math.max(0, Math.min(1, (anchorY - rect.top) / rect.height)) }; } return null; } function restoreFontAnchor(anchor) { if (!anchor || !anchor.node.isConnected || !activeReader()) return; var rect = anchor.node.getBoundingClientRect(); if (!(rect.height > 0)) return; var delta = rect.top + rect.height * anchor.ratio - anchor.y; if (Number.isFinite(delta)) state.reader.scrollTop += delta; } function setToolbarCollapsed(collapsed) { var previous = toolbarCollapsed; toolbarCollapsed = !!collapsed; try { localStorage.setItem(toolbarKey, toolbarCollapsed ? '1' : '0'); } catch (_) {} if (!state.toolbar || !state.toolbarHandle) return; var top = state.reader ? state.reader.scrollTop : 0; var height = state.toolbar.getBoundingClientRect().height || state.toolbar.offsetHeight || 48; state.toolbar.hidden = toolbarCollapsed; state.toolbar.style.setProperty('display', toolbarCollapsed ? 'none' : 'flex', 'important'); state.toolbarHandle.hidden = !toolbarCollapsed; state.toolbarHandle.style.setProperty('display', toolbarCollapsed ? 'block' : 'none', 'important'); if (state.reader && previous !== toolbarCollapsed) { if (toolbarCollapsed) state.reader.scrollTop = Math.max(0, top - height); else if (top > 0) state.reader.scrollTop = top + (state.toolbar.getBoundingClientRect().height || state.toolbar.offsetHeight || height); } } function themeFor(id) { for (var i = 0; i < themes.length; i++) if (themes[i].id === id) return themes[i]; return themes[1]; } function themeBackground(theme) { if (!theme.image) return 'none'; var image = 'url("' + theme.image + '")'; return theme.tint ? 'linear-gradient(' + theme.tint + ',' + theme.tint + '),' + image : image; } function applyTheme(id) { var theme = themeFor(id); currentTheme = theme.id; try { localStorage.setItem(themeKey, currentTheme); } catch (_) {} if (!state.reader || !state.paper) return; state.reader.setAttribute('data-bm-reader-theme', theme.id); state.reader.style.setProperty('background-color', theme.bg, 'important'); state.reader.style.setProperty('color', theme.text, 'important'); state.paper.style.setProperty('background-color', theme.bg, 'important'); state.paper.style.setProperty('background-image', themeBackground(theme), 'important'); state.toolbar.style.setProperty('background-color', theme.bar, 'important'); var buttons = state.toolbar.querySelectorAll('[data-bm-theme-choice]'); for (var i = 0; i < buttons.length; i++) { var selected = buttons[i].getAttribute('data-bm-theme-choice') === theme.id; buttons[i].setAttribute('aria-pressed', selected ? 'true' : 'false'); buttons[i].style.setProperty('border-color', selected ? (theme.id === 'night' ? '#eee' : '#48423a') : '#aaa', 'important'); buttons[i].style.setProperty('box-shadow', selected ? '0 0 0 2px ' + theme.bar : 'none', 'important'); } var fontButtons = state.toolbar.querySelectorAll('[data-bm-font-step], [data-bm-toc-open], [data-bm-resume]'); for (var j = 0; j < fontButtons.length; j++) { fontButtons[j].style.setProperty('color', theme.text, 'important'); fontButtons[j].style.setProperty('border-color', theme.text, 'important'); fontButtons[j].style.setProperty('background-color', theme.id === 'night' ? 'rgba(255,255,255,.1)' : 'rgba(255,255,255,.22)', 'important'); } var fontValue = state.toolbar.querySelector('[data-bm-font-value]'); if (fontValue) fontValue.style.setProperty('color', theme.text, 'important'); var collapse = state.toolbar.querySelector('[data-bm-toolbar-collapse]'); if (collapse) collapse.style.setProperty('color', theme.text, 'important'); if (state.toolbarHandle) { state.toolbarHandle.style.setProperty('background-color', theme.bar, 'important'); state.toolbarHandle.style.setProperty('color', theme.text, 'important'); } [state.tocPanel, state.progressPanel].forEach(function (panel) { if (panel) { panel.style.setProperty('background-color', theme.bg, 'important'); panel.style.setProperty('background-image', themeBackground(theme), 'important'); panel.style.setProperty('color', theme.text, 'important'); var panelHeader = panel.querySelector('[data-bm-toc-header], [data-bm-progress-header]'); if (panelHeader) panelHeader.style.setProperty('background-color', theme.bar, 'important'); var panelButtons = panel.querySelectorAll('button'); for (var k = 0; k < panelButtons.length; k++) { panelButtons[k].style.setProperty('color', theme.text, 'important'); } } }); } function installReaderStyle() { if (document.getElementById('bm-reader-theme-style')) return; var style = document.createElement('style'); style.id = 'bm-reader-theme-style'; style.textContent = '.via-reader-body[data-bm-auto-reader]{position:fixed;top:0;right:0;bottom:0;left:0;' + 'overflow:auto;z-index:2147483647!important;overscroll-behavior:contain}' + '.via-reader-body[data-bm-auto-reader] .via-reader-header{margin:0 16px 24px;text-align:left}' + '.via-reader-body[data-bm-auto-reader] .via-reader-header h1{padding:24px 0 0;margin:0;font-size:1.4em;line-height:1.6}' + '.via-reader-body[data-bm-auto-reader] .via-reader-content{margin:10px 16px 0;overflow-wrap:break-word}' + '.via-reader-body[data-bm-reader-theme] .via-reader-content{' + 'text-align:left!important;color:inherit!important}' + '.via-reader-body[data-bm-reader-theme] .via-reader-header,' + '.via-reader-body[data-bm-reader-theme] .via-reader-header h1,' + '.via-reader-body[data-bm-reader-theme] .via-reader-content h1,' + '.via-reader-body[data-bm-reader-theme] .via-reader-content h2,' + '.via-reader-body[data-bm-reader-theme] .via-reader-content p{' + 'color:inherit!important}' + '.via-reader-body[data-bm-reader-theme] .via-reader-content p:not([style*="text-align"]){' + 'font-size:inherit!important;line-height:1.7!important;padding:0!important;' + 'margin:0 0 .45em!important;text-align:left!important;text-indent:2em!important;' + 'overflow-wrap:break-word}' + '.via-reader-body[data-bm-reader-theme] .via-reader-content h1,' + '.via-reader-body[data-bm-reader-theme] .via-reader-content h2{' + 'line-height:1.5!important;text-indent:0!important;margin:1em 0 .6em!important}' + '.via-reader-body[data-bm-reader-theme="night"] .via-reader-content a,' + '.via-reader-body[data-bm-reader-theme="night"] .via-reader-header a{' + 'color:#9ec8ff!important}' + '.via-reader-body [data-bm-toolbar-expand]:active,' + '.via-reader-body [data-bm-toolbar-expand]:focus-visible{' + 'opacity:.72!important}'; (document.head || document.documentElement).appendChild(style); } function installThemeControls(reader) { var frame = reader.firstElementChild; if (!frame || !frame.querySelector('.via-reader-header')) return; // 始终覆盖整个 WebView,避免旧自定义 CSS 给阅读浮层留下侧边空白。 reader.style.setProperty('position', 'fixed', 'important'); ['top', 'right', 'bottom', 'left'].forEach(function (side) { reader.style.setProperty(side, '0', 'important'); }); reader.style.setProperty('width', '100%', 'important'); // 释放前文和调整字号时由脚本保持可见段落,避免浏览器再次补偿滚动。 reader.style.setProperty('overflow-anchor', 'none', 'important'); var paper = document.createElement('div'); paper.setAttribute('data-bm-theme-paper', ''); paper.style.cssText = 'position:fixed;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none;' + 'background-position:center center;background-size:cover;background-repeat:no-repeat;'; reader.insertBefore(paper, frame); frame.style.setProperty('position', 'relative'); frame.style.setProperty('z-index', '1'); frame.style.setProperty('width', '100%', 'important'); var bar = document.createElement('div'); bar.setAttribute('data-bm-theme-bar', ''); bar.setAttribute('role', 'group'); bar.setAttribute('aria-label', '阅读背景与字号'); bar.style.cssText = 'position:sticky;top:0;z-index:2;display:flex;flex-wrap:nowrap;gap:3px;' + 'align-items:center;box-sizing:border-box;width:100%;' + 'padding:4px;min-height:40px;overflow:hidden;' + 'border-bottom:1px solid rgba(90,80,70,.18);'; var palette = document.createElement('div'); palette.setAttribute('data-bm-theme-palette', ''); palette.style.cssText = 'display:flex;flex:1 1 auto;min-width:113px;gap:3px;' + 'align-items:center;overflow-x:auto;white-space:nowrap;'; themes.forEach(function (theme) { var button = document.createElement('button'); button.type = 'button'; button.setAttribute('data-bm-theme-choice', theme.id); button.setAttribute('aria-label', theme.label); button.title = theme.label; button.style.cssText = 'flex:0 0 26px;width:26px;height:26px;box-sizing:border-box;' + 'padding:0;border:2px solid #aaa;border-radius:5px;cursor:pointer;' + 'background-position:center;background-size:cover;background-repeat:no-repeat;'; button.style.setProperty('background-color', theme.bg, 'important'); button.style.setProperty('background-image', themeBackground(theme), 'important'); palette.appendChild(button); }); bar.appendChild(palette); var tocButton = document.createElement('button'); tocButton.type = 'button'; tocButton.setAttribute('data-bm-toc-open', ''); tocButton.setAttribute('aria-label', '打开章节目录'); tocButton.textContent = '目录'; tocButton.style.cssText = 'flex:0 0 34px;width:34px;height:32px;box-sizing:border-box;' + 'padding:0;border:1px solid currentColor;border-radius:5px;' + 'font-size:13px;font-weight:600;cursor:pointer;'; bar.appendChild(tocButton); var resumeButton = document.createElement('button'); resumeButton.type = 'button'; resumeButton.setAttribute('data-bm-resume', ''); resumeButton.setAttribute('aria-label', '查看阅读进度'); resumeButton.title = '查看阅读进度'; resumeButton.textContent = '进度'; resumeButton.style.cssText = 'flex:0 0 34px;width:34px;height:32px;box-sizing:border-box;' + 'padding:0;border:1px solid currentColor;border-radius:5px;' + 'font-size:13px;font-weight:600;cursor:pointer;'; bar.appendChild(resumeButton); var fontControls = document.createElement('div'); fontControls.setAttribute('data-bm-font-controls', ''); fontControls.style.cssText = 'display:flex;flex:0 0 auto;gap:3px;align-items:center;margin-left:auto;'; [ { step: -1, text: 'A−', label: '缩小字号' }, { step: 1, text: 'A+', label: '放大字号' } ].forEach(function (item, index) { if (index) { var value = document.createElement('span'); value.setAttribute('data-bm-font-value', ''); value.setAttribute('role', 'status'); value.setAttribute('aria-live', 'polite'); value.style.cssText = 'flex:0 0 18px;width:18px;text-align:center;' + 'font-size:11px;font-weight:600;line-height:1;'; fontControls.appendChild(value); } var button = document.createElement('button'); button.type = 'button'; button.setAttribute('data-bm-font-step', String(item.step)); button.setAttribute('aria-label', item.label); button.title = item.label; button.textContent = item.text; button.style.cssText = 'flex:0 0 30px;width:30px;height:32px;box-sizing:border-box;' + 'padding:0;border:1px solid currentColor;border-radius:5px;' + 'font-size:17px;font-weight:700;line-height:1;cursor:pointer;'; fontControls.appendChild(button); }); var collapse = document.createElement('button'); collapse.type = 'button'; collapse.setAttribute('data-bm-toolbar-collapse', ''); collapse.setAttribute('aria-label', '收起阅读工具栏'); collapse.textContent = '⌃'; collapse.style.cssText = 'flex:0 0 24px;width:24px;height:32px;box-sizing:border-box;' + 'padding:0;border:0;background:none;font-size:24px;line-height:1;cursor:pointer;'; bar.appendChild(fontControls); bar.appendChild(collapse); frame.insertBefore(bar, frame.firstChild); var handle = document.createElement('button'); handle.type = 'button'; handle.setAttribute('data-bm-toolbar-expand', ''); handle.setAttribute('aria-label', '展开阅读工具栏'); handle.textContent = '☰'; handle.style.cssText = 'position:fixed;top:6px;right:6px;z-index:5;opacity:.28;' + 'width:34px;height:34px;padding:0;border:1px solid currentColor;' + 'border-radius:7px;font-size:18px;line-height:1;cursor:pointer;'; reader.appendChild(handle); state.paper = paper; state.toolbar = bar; state.toolbarHandle = handle; installCataloguePanel(reader); installProgressPanel(reader); applyTheme(currentTheme); applyFontSize(fontSize); updateResumeButton(); setToolbarCollapsed(toolbarCollapsed); } function installCataloguePanel(reader) { var panel = document.createElement('div'); panel.setAttribute('data-bm-toc-panel', ''); panel.setAttribute('role', 'dialog'); panel.setAttribute('aria-label', '章节目录'); panel.hidden = true; panel.style.cssText = 'position:fixed;top:0;right:0;bottom:0;left:0;z-index:6;' + 'box-sizing:border-box;width:100%;overflow-y:auto;overscroll-behavior:contain;' + 'background-position:center;background-size:cover;background-repeat:no-repeat;'; panel.style.setProperty('display', 'none', 'important'); var header = document.createElement('div'); header.setAttribute('data-bm-toc-header', ''); header.style.cssText = 'position:sticky;top:0;z-index:1;display:flex;' + 'align-items:center;justify-content:space-between;box-sizing:border-box;' + 'min-height:52px;padding:8px 14px;border-bottom:1px solid rgba(80,70,60,.2);'; var title = document.createElement('strong'); title.textContent = '章节目录'; title.style.cssText = 'font-size:18px;line-height:1.4;'; var close = document.createElement('button'); close.type = 'button'; close.setAttribute('data-bm-toc-close', ''); close.setAttribute('aria-label', '返回阅读'); close.textContent = '返回阅读 ×'; close.style.cssText = 'padding:6px 8px;border:1px solid currentColor;' + 'border-radius:5px;background:none;font-size:14px;'; header.appendChild(title); header.appendChild(close); panel.appendChild(header); var status = document.createElement('div'); status.setAttribute('data-bm-toc-status', ''); status.setAttribute('role', 'status'); status.style.cssText = 'padding:12px 16px;font-size:14px;line-height:1.5;'; status.hidden = true; panel.appendChild(status); var pages = document.createElement('div'); pages.setAttribute('data-bm-toc-pages', ''); pages.setAttribute('aria-label', '目录分页'); pages.style.cssText = 'display:flex;gap:5px;overflow-x:auto;padding:10px 12px;' + 'box-sizing:border-box;white-space:nowrap;'; panel.appendChild(pages); var list = document.createElement('div'); list.setAttribute('data-bm-toc-list', ''); list.style.cssText = 'padding:0 8px 24px;box-sizing:border-box;'; panel.appendChild(list); reader.appendChild(panel); state.tocPanel = panel; state.tocStatus = status; state.tocPages = pages; state.tocList = list; } function installProgressPanel(reader) { var panel = document.createElement('div'); panel.setAttribute('data-bm-progress-panel', ''); panel.setAttribute('role', 'dialog'); panel.setAttribute('aria-label', '阅读进度'); panel.hidden = true; panel.style.cssText = 'position:fixed;top:0;right:0;bottom:0;left:0;z-index:6;' + 'box-sizing:border-box;width:100%;overflow-y:auto;overscroll-behavior:contain;' + 'background-position:center;background-size:cover;background-repeat:no-repeat;'; panel.style.setProperty('display', 'none', 'important'); var header = document.createElement('div'); header.setAttribute('data-bm-progress-header', ''); header.style.cssText = 'position:sticky;top:0;z-index:1;display:flex;' + 'align-items:center;justify-content:space-between;box-sizing:border-box;' + 'min-height:52px;padding:8px 14px;border-bottom:1px solid rgba(80,70,60,.2);'; var title = document.createElement('strong'); title.textContent = '阅读进度'; title.style.cssText = 'font-size:18px;line-height:1.4;'; var close = document.createElement('button'); close.type = 'button'; close.setAttribute('data-bm-progress-close', ''); close.setAttribute('aria-label', '返回阅读'); close.textContent = '返回阅读 ×'; close.style.cssText = 'padding:6px 8px;border:1px solid currentColor;' + 'border-radius:5px;background:none;font-size:14px;'; header.appendChild(title); if (reader.hasAttribute('data-bm-auto-reader')) { var exit = document.createElement('button'); exit.type = 'button'; exit.textContent = '退出阅读'; exit.setAttribute('data-bm-reader-exit', ''); exit.style.cssText = 'padding:6px 8px;border:1px solid currentColor;border-radius:5px;background:none;font-size:14px;'; header.appendChild(exit); } header.appendChild(close); panel.appendChild(header); var status = document.createElement('div'); status.setAttribute('data-bm-progress-status', ''); status.setAttribute('role', 'status'); status.style.cssText = 'padding:12px 16px;font-size:14px;line-height:1.5;'; status.hidden = true; panel.appendChild(status); installBackupControls(panel); var memoryNote = document.createElement('div'); memoryNote.setAttribute('data-bm-memory-note', ''); memoryNote.textContent = '较早的正文已释放。要回看,可从进度或目录重新打开。'; memoryNote.style.cssText = 'padding:6px 16px;font-size:12px;line-height:1.5;opacity:.75;'; memoryNote.hidden = !state.compactedPages; panel.appendChild(memoryNote); var list = document.createElement('div'); list.setAttribute('data-bm-progress-list', ''); list.style.cssText = 'padding:8px 12px 28px;box-sizing:border-box;'; panel.appendChild(list); reader.appendChild(panel); state.progressPanel = panel; state.progressList = list; state.progressStatus = status; } // Backups contain owned reader settings and positions only, never chapter text or site credentials. var backupMaxBytes = 5 * 1024 * 1024; var backupFormat = 'boluomao-via-reader-backup'; function backupObject(value) { return !!value && typeof value === 'object' && !Array.isArray(value); } function backupInteger(value, minimum, maximum) { return typeof value === 'number' && Number.isInteger(value) && value >= minimum && value <= maximum; } function backupError(message) { throw new Error(message || '备份内容格式不正确,未修改现有进度。'); } function backupReadUrl(value, id) { if (typeof value !== 'string' || value.length > 500) return null; try { var url = new URL(value); if (url.protocol !== 'https:' || url.origin !== origin || url.username || url.password || url.hash || !new RegExp('^/read/' + id + '/\\d+\\.html$').test(url.pathname)) return null; var valid = true; var pages = 0; url.searchParams.forEach(function (item, key) { if (key !== 'p' || !/^[1-9]\d*$/.test(item) || Number(item) > 10000 || ++pages > 1) valid = false; }); if (!valid) return null; if (url.searchParams.get('p') === '1') url.searchParams.delete('p'); return url; } catch (_) { return null; } } function backupPosition(value, id, orders, titles) { if (value === null || typeof value === 'undefined') return null; if (!backupObject(value)) backupError(); var url = backupReadUrl(value.url, id); if (!url || !backupInteger(value.index, 0, 100000) || typeof value.ratio !== 'number' || !Number.isFinite(value.ratio) || value.ratio < 0 || value.ratio > 1 || typeof value.time !== 'number' || !Number.isFinite(value.time) || value.time < 0 || value.time > 8640000000000000 || (typeof value.order !== 'undefined' && !backupInteger(value.order, 0, 100000)) || (typeof value.title !== 'undefined' && (typeof value.title !== 'string' || value.title.length > 120))) backupError(); return { url: url.href, index: value.index, ratio: value.ratio, time: value.time, order: orders.get(url.pathname) || value.order || 0, title: titles.get(url.pathname) || cleanChapterTitle(value.title || '').slice(0, 120) }; } function backupMap(value, id, kind) { if (!Array.isArray(value) || value.length > 100000) backupError(); var map = new Map(); value.forEach(function (entry) { if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== 'string' || !new RegExp('^/read/' + id + '/\\d+\\.html$').test(entry[0]) || map.has(entry[0])) backupError(); if (kind === 'orders') { if (!backupInteger(entry[1], 1, 100000)) backupError(); map.set(entry[0], entry[1]); } else { if (typeof entry[1] !== 'string' || entry[1].length > 120) backupError(); map.set(entry[0], cleanChapterTitle(entry[1])); } }); return map; } function validateBackupBook(value) { if (!backupObject(value) || typeof value.id !== 'string' || !/^\d{1,18}$/.test(value.id) || !backupObject(value.history) || !Array.isArray(value.history.recent) || value.history.recent.length > 1000 || !backupInteger(value.catalogPage, 1, 100)) backupError(); var orders = backupMap(value.chapterOrders, value.id, 'orders'); var titles = backupMap(value.chapterTitles, value.id, 'titles'); return { id: value.id, latest: backupPosition(value.latest, value.id, orders, titles), history: { furthest: backupPosition(value.history.furthest, value.id, orders, titles), recent: value.history.recent.map(function (entry) { var position = backupPosition(entry, value.id, orders, titles); if (!position) backupError(); return position; }) }, chapterOrders: Array.from(orders), chapterTitles: Array.from(titles), catalogPage: value.catalogPage }; } function validateBackup(value) { if (!backupObject(value) || value.format !== backupFormat || value.schemaVersion !== 1 || !backupObject(value.settings) || !Array.isArray(value.books) || value.books.length > 500 || !themes.some(function (theme) { return theme.id === value.settings.theme; }) || !backupInteger(value.settings.fontSize, 16, 34) || typeof value.settings.toolbarCollapsed !== 'boolean') { backupError('这不是支持的阅读备份,或备份版本不兼容;现有进度未修改。'); } var ids = new Set(); var books = value.books.map(function (book) { var checked = validateBackupBook(book); if (ids.has(checked.id)) backupError(); ids.add(checked.id); return checked; }); return { format: backupFormat, schemaVersion: 1, scriptVersion: '1.8.0', exportedAt: typeof value.exportedAt === 'string' && value.exportedAt.length <= 40 ? value.exportedAt : '', settings: { theme: value.settings.theme, fontSize: value.settings.fontSize, toolbarCollapsed: value.settings.toolbarCollapsed }, books: books }; } function backupStoredJson(key, fallback) { var text = localStorage.getItem(key); if (text === null) return fallback; try { return JSON.parse(text); } catch (_) { backupError('已有阅读记录损坏,备份操作已停止;现有记录未修改。'); } } function collectBackupBook(id) { var prefix = 'bm-reader-'; var latest = backupStoredJson(prefix + 'progress-' + id, null); var history = backupStoredJson(prefix + 'progress-history-' + id + '-v1', { furthest: null, recent: [] }); var orders = backupStoredJson(prefix + 'chapter-order-' + id + '-v1', []); var titles = backupStoredJson(prefix + 'chapter-title-' + id + '-v1', []); var pageText = localStorage.getItem(prefix + 'catalog-page-' + id); var page = pageText === null ? 1 : Number(pageText); return validateBackupBook({ id: id, latest: latest, history: history, chapterOrders: orders, chapterTitles: titles, catalogPage: page }); } function collectBackup() { var ids = new Set(); for (var i = 0; i < localStorage.length; i++) { var key = localStorage.key(i); var found; if ((found = /^bm-reader-progress-(\d{1,18})$/.exec(key)) || (found = /^bm-reader-progress-history-(\d{1,18})-v1$/.exec(key)) || (found = /^bm-reader-chapter-(?:order|title)-(\d{1,18})-v1$/.exec(key)) || (found = /^bm-reader-catalog-page-(\d{1,18})$/.exec(key))) ids.add(found[1]); } if (ids.size > 500) backupError('书籍记录超过备份上限,未生成文件。'); return validateBackup({ format: backupFormat, schemaVersion: 1, scriptVersion: '1.8.0', exportedAt: new Date().toISOString(), settings: { theme: currentTheme, fontSize: fontSize, toolbarCollapsed: toolbarCollapsed }, books: Array.from(ids).sort().map(collectBackupBook) }); } function backupWithin(first, second, id) { var a = backupReadUrl(first.url, id); var b = backupReadUrl(second.url, id); if (a.pathname !== b.pathname) return null; return progressPage(a) - progressPage(b) || first.index - second.index || first.ratio - second.ratio; } function mergeBackupBook(local, incoming) { var id = incoming.id; var orders = new Map(incoming.chapterOrders); var titles = new Map(incoming.chapterTitles); local.chapterOrders.forEach(function (entry) { orders.set(entry[0], entry[1]); }); local.chapterTitles.forEach(function (entry) { if (entry[1]) titles.set(entry[0], entry[1]); }); function normalize(entry) { return backupPosition(entry, id, orders, titles); } var latest = !local.latest ? incoming.latest : !incoming.latest || local.latest.time >= incoming.latest.time ? local.latest : incoming.latest; var recent = new Map(); [local.history.furthest, incoming.history.furthest, local.latest, incoming.latest] .concat(local.history.recent, incoming.history.recent).forEach(function (entry) { if (!entry) return; var position = normalize(entry); var path = backupReadUrl(position.url, id).pathname; var old = recent.get(path); if (!old) { recent.set(path, position); return; } var winner = backupWithin(position, old, id) > 0 ? position : old; winner.time = Math.max(position.time, old.time); recent.set(path, winner); }); var furthest = normalize(local.history.furthest || local.latest || incoming.history.furthest || incoming.latest); recent.forEach(function (entry) { if (!furthest) { furthest = entry; return; } var within = backupWithin(entry, furthest, id); if ((within !== null && within > 0) || (within === null && entry.order && furthest.order && entry.order > furthest.order)) { furthest = entry; } }); return { id: id, latest: normalize(latest), history: { furthest: furthest, recent: Array.from(recent.values()).sort(function (a, b) { return b.time - a.time; }).slice(0, 1000) }, chapterOrders: Array.from(orders), chapterTitles: Array.from(titles), catalogPage: local.catalogPage || incoming.catalogPage }; } function backupWrites(book, writes) { var id = book.id; writes.set('bm-reader-progress-' + id, JSON.stringify(book.latest)); writes.set('bm-reader-progress-history-' + id + '-v1', JSON.stringify(book.history)); writes.set('bm-reader-chapter-order-' + id + '-v1', JSON.stringify(book.chapterOrders)); writes.set('bm-reader-chapter-title-' + id + '-v1', JSON.stringify(book.chapterTitles)); writes.set('bm-reader-catalog-page-' + id, String(book.catalogPage)); } function applyBackupData(data) { var checked = validateBackup(data); var writes = new Map(); var merged = []; checked.books.forEach(function (incoming) { var local = collectBackupBook(incoming.id); var result = mergeBackupBook(local, incoming); if (localStorage.getItem('bm-reader-catalog-page-' + incoming.id) === null) result.catalogPage = incoming.catalogPage; backupWrites(result, writes); merged.push(result); }); writes.set(themeKey, checked.settings.theme); writes.set(fontKey, String(checked.settings.fontSize)); writes.set(toolbarKey, checked.settings.toolbarCollapsed ? '1' : '0'); var before = new Map(); writes.forEach(function (_, key) { before.set(key, localStorage.getItem(key)); }); var applied = []; try { writes.forEach(function (value, key) { localStorage.setItem(key, value); applied.push(key); }); } catch (_) { var rollbackFailed = false; applied.reverse().forEach(function (key) { try { var old = before.get(key); if (old === null) localStorage.removeItem(key); else localStorage.setItem(key, old); } catch (ignored) { rollbackFailed = true; } }); backupError(rollbackFailed ? '存储空间不足,部分记录无法回滚;请保留备份文件并释放浏览器存储后重试。' : '存储空间不足,恢复已撤销;现有记录未修改。'); } for (var i = 0; i < merged.length; i++) { if (merged[i].id !== bookId) continue; state.chapterOrders = new Map(merged[i].chapterOrders); state.chapterTitles = new Map(merged[i].chapterTitles); state.savedProgress = merged[i].latest; state.progressHistory = merged[i].history; state.tocPage = merged[i].catalogPage; state.progressTouched = false; if (state.progressTimer) { clearTimeout(state.progressTimer); state.progressTimer = null; } break; } applyTheme(checked.settings.theme); applyFontSize(checked.settings.fontSize); setToolbarCollapsed(checked.settings.toolbarCollapsed); updateResumeButton(); renderProgressHistory(); setBackupStatus('已合并 ' + checked.books.length + ' 本书的进度,背景、字号和工具栏设置已恢复。'); return checked; } function setBackupStatus(message) { if (state.backupStatus) state.backupStatus.textContent = message || ''; } function toggleBackupText(force) { if (!state.backupTextPanel) return; var show = typeof force === 'boolean' ? force : state.backupTextPanel.hidden; state.backupTextPanel.hidden = !show; state.backupTextPanel.style.setProperty('display', show ? 'block' : 'none', 'important'); } function exportBackup() { try { if (state.progressTouched) saveProgressNow(true); var data = collectBackup(); var text = JSON.stringify(data, null, 2); if (text.length > backupMaxBytes || new Blob([text]).size > backupMaxBytes) backupError('备份超过 5 MB 上限,未生成文件。'); if (state.backupText) state.backupText.value = text; if (!window.URL || !URL.createObjectURL) { toggleBackupText(true); setBackupStatus('此浏览器不支持文件下载,请复制下面的备份文本保存。'); return; } if (state.backupDownloadUrl) URL.revokeObjectURL(state.backupDownloadUrl); if (state.backupDownloadAnchor) state.backupDownloadAnchor.remove(); var url = URL.createObjectURL(new Blob([text], { type: 'application/json;charset=utf-8' })); var anchor = document.createElement('a'); anchor.href = url; anchor.download = '菠萝猫阅读备份-' + new Date().toISOString().slice(0, 10) + '.json'; anchor.style.display = 'none'; state.backupDownloadAnchor = anchor; state.backupDownloadUrl = url; document.body.appendChild(anchor); anchor.click(); setBackupStatus('已生成 ' + data.books.length + ' 本书的备份。若手机未下载文件,点“备份文本”复制保存。'); setTimeout(function () { if (state.backupDownloadAnchor === anchor) { state.backupDownloadAnchor = null; state.backupDownloadUrl = null; } anchor.remove(); URL.revokeObjectURL(url); }, 60000); } catch (error) { setBackupStatus(error.message || '备份生成失败。'); } } function restoreBackupText() { try { var text = state.backupText ? state.backupText.value.trim() : ''; if (!text || text.length > backupMaxBytes || new Blob([text]).size > backupMaxBytes) backupError('请选择或粘贴不超过 5 MB 的阅读备份。'); var data; try { data = JSON.parse(text); } catch (_) { backupError('备份不是有效 JSON;现有进度未修改。'); } applyBackupData(data); } catch (error) { setBackupStatus(error.message || '备份恢复失败,现有记录未修改。'); } } function importBackupFile(file) { if (!file) return; if (!backupInteger(file.size, 1, backupMaxBytes)) { setBackupStatus('请选择不超过 5 MB 的阅读备份文件。'); return; } var reader = new FileReader(); setBackupStatus('正在读取备份文件…'); reader.onload = function () { if (state.backupText) state.backupText.value = String(reader.result || ''); restoreBackupText(); }; reader.onerror = function () { setBackupStatus('文件读取失败,请用“备份文本”粘贴恢复。'); }; try { reader.readAsText(file, 'UTF-8'); } catch (_) { setBackupStatus('无法打开此文件,请用“备份文本”粘贴恢复。'); } } function copyBackupText() { var text = state.backupText && state.backupText.value; if (!text) { setBackupStatus('先点“导出备份”生成文本,或粘贴已有备份。'); return; } function manualCopy() { toggleBackupText(true); state.backupText.focus(); state.backupText.select(); var copied = false; try { copied = document.execCommand('copy'); } catch (_) {} setBackupStatus(copied ? '备份文本已复制,请保存到手机文件或笔记中。' : '请长按下面的文本,全选并复制保存。'); } if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(function () { setBackupStatus('备份文本已复制,请保存到手机文件或笔记中。'); }, manualCopy); } else manualCopy(); } function installBackupControls(panel) { var area = document.createElement('div'); area.setAttribute('data-bm-backup-area', ''); area.style.cssText = 'padding:10px 12px 4px;box-sizing:border-box;font-size:14px;line-height:1.5;'; var row = document.createElement('div'); row.style.cssText = 'display:flex;flex-wrap:wrap;gap:8px;'; [['export', '导出备份'], ['import', '导入恢复'], ['toggle-text', '备份文本']].forEach(function (item) { var button = document.createElement('button'); button.type = 'button'; button.setAttribute('data-bm-backup-' + item[0], ''); button.textContent = item[1]; button.style.cssText = 'padding:6px 10px;border:1px solid currentColor;border-radius:5px;background:none;font-size:14px;'; row.appendChild(button); }); area.appendChild(row); var status = document.createElement('div'); status.setAttribute('data-bm-backup-status', ''); status.setAttribute('role', 'status'); status.style.cssText = 'font-size:12px;line-height:1.5;padding-top:6px;'; status.textContent = '备份全部书的阅读进度和外观设置。'; area.appendChild(status); state.backupStatus = status; var file = document.createElement('input'); file.type = 'file'; file.accept = '.json,application/json,text/plain'; file.setAttribute('data-bm-backup-file', ''); file.style.display = 'none'; file.addEventListener('change', function () { var selected = file.files && file.files[0]; file.value = ''; importBackupFile(selected); }); area.appendChild(file); state.backupFile = file; var fallback = document.createElement('div'); fallback.setAttribute('data-bm-backup-text-panel', ''); fallback.hidden = true; fallback.style.setProperty('display', 'none', 'important'); var help = document.createElement('div'); help.textContent = '文件下载或选择失败时,可复制备份文本保存;以后粘贴到这里恢复。'; help.style.cssText = 'padding:8px 0;font-size:12px;'; fallback.appendChild(help); var text = document.createElement('textarea'); text.setAttribute('data-bm-backup-text', ''); text.setAttribute('aria-label', '阅读备份 JSON 文本'); text.placeholder = '粘贴阅读备份 JSON'; text.spellcheck = false; text.style.cssText = 'display:block;width:100%;height:120px;box-sizing:border-box;border:1px solid currentColor;border-radius:5px;' + 'padding:8px;background:none;color:inherit;font-size:12px;font-family:monospace;line-height:1.5;'; fallback.appendChild(text); state.backupText = text; var actions = document.createElement('div'); actions.style.cssText = 'display:flex;gap:8px;padding-top:8px;'; [['copy', '复制文本'], ['restore-text', '从文本恢复']].forEach(function (item) { var button = document.createElement('button'); button.type = 'button'; button.setAttribute('data-bm-backup-' + item[0], ''); button.textContent = item[1]; button.style.cssText = 'padding:6px 10px;border:1px solid currentColor;border-radius:5px;background:none;font-size:14px;'; actions.appendChild(button); }); fallback.appendChild(actions); area.appendChild(fallback); state.backupTextPanel = fallback; panel.insertBefore(area, panel.children[1] || null); } function setProgressStatus(message) { if (!state.progressStatus) return; state.progressStatus.textContent = message || ''; state.progressStatus.hidden = !message; } function closeProgressPanel() { if (!state.progressPanel) return; state.progressOpen = false; state.progressSeq++; stopCatalogueRequest(); state.progressPanel.hidden = true; state.progressPanel.style.setProperty('display', 'none', 'important'); setProgressStatus(''); schedule(); } function openProgressPanel() { if (!state.progressPanel || state.progressOpen) return; if (state.tocOpen) closeCatalogue(); if (state.progressTimer) { clearTimeout(state.progressTimer); state.progressTimer = null; } if (state.progressTouched || !normalizeProgress(state.savedProgress)) saveProgressNow(); state.progressOpen = true; if (state.timer) { clearTimeout(state.timer); state.timer = null; } state.progressPanel.hidden = false; state.progressPanel.style.setProperty('display', 'block', 'important'); setProgressStatus(''); renderProgressHistory(); } function progressLabel(progress) { return progress.title || '章节名称待补全'; } function addProgressChoice(label, progress) { var button = document.createElement('button'); button.type = 'button'; button.setAttribute('data-bm-progress-url', progress.url); button.setAttribute('data-bm-progress-index', String(progress.index)); button.setAttribute('data-bm-progress-ratio', String(progress.ratio)); button.style.cssText = 'display:block;width:100%;box-sizing:border-box;padding:12px 10px;' + 'border:0;border-bottom:1px solid rgba(90,80,70,.18);' + 'background:none;text-align:left;font-size:16px;line-height:1.5;'; var caption = document.createElement('strong'); caption.textContent = label; caption.style.cssText = 'display:block;font-size:12px;opacity:.75;font-weight:600;'; var location = document.createElement('span'); location.setAttribute('data-bm-progress-title', ''); location.textContent = progressLabel(progress); location.style.cssText = 'display:block;font-weight:600;'; var detail = document.createElement('span'); detail.setAttribute('data-bm-progress-detail', ''); var progressUrl = readUrl(progress.url); detail.textContent = '第' + progressPage(progressUrl) + '页 · 第' + (progress.index + 1) + '段'; detail.style.cssText = 'display:block;font-size:13px;opacity:.75;'; button.appendChild(caption); button.appendChild(location); button.appendChild(detail); state.progressList.appendChild(button); } function renderProgressHistory() { if (!state.progressList) return; state.progressList.textContent = ''; var furthest = normalizeProgress(state.progressHistory.furthest); if (!furthest && !state.progressHistory.recent.length) { var empty = document.createElement('div'); empty.textContent = '还没有保存的阅读进度。'; empty.style.cssText = 'padding:16px 10px;font-size:14px;'; state.progressList.appendChild(empty); return; } if (furthest) addProgressChoice('最远已读 · 固定在顶部', furthest); var recent = state.progressHistory.recent.slice().sort(function (a, b) { return b.time - a.time; }); for (var i = 0; i < recent.length; i++) { var entry = normalizeProgress(recent[i]); if (!entry || (furthest && sameProgressPosition(entry, furthest))) continue; addProgressChoice(!furthest ? '最近打开' : entry.order ? '其他位置' : '其他位置 · 顺序待确认', entry); } applyTheme(currentTheme); } function setCatalogueStatus(message) { if (!state.tocStatus) return; state.tocStatus.textContent = message || ''; state.tocStatus.hidden = !message; } function closeCatalogue() { if (!state.tocPanel) return; state.tocOpen = false; state.tocSeq++; stopCatalogueRequest(); state.tocPanel.hidden = true; state.tocPanel.style.setProperty('display', 'none', 'important'); setCatalogueStatus(''); schedule(); } function openCatalogue() { if (!state.tocPanel || state.tocOpen) return; if (state.progressTimer) { clearTimeout(state.progressTimer); state.progressTimer = null; } if (state.progressTouched || !normalizeProgress(state.savedProgress)) saveProgressNow(); state.tocOpen = true; if (state.timer) { clearTimeout(state.timer); state.timer = null; } state.tocPanel.hidden = false; state.tocPanel.style.setProperty('display', 'block', 'important'); loadCatalogue(state.tocPage); } function stopCatalogueRequest() { if (state.tocController) { state.tocController.abort(); state.tocController = null; } } async function fetchInertPage(url, kind) { var controller = typeof AbortController === 'function' ? new AbortController() : null; state.tocController = controller; var timeout; try { return await Promise.race([(async function () { var response = await fetch(url.href, { credentials: 'same-origin', redirect: 'manual', signal: controller ? controller.signal : undefined }); if (response.type === 'opaqueredirect' || (response.status >= 300 && response.status < 400)) { throw new Error(kind + '需要登录或验证,当前阅读已保留'); } if (!response.ok) throw new Error(kind + '加载失败(' + response.status + '),当前阅读已保留'); if (response.url) { var finalUrl = siteUrl(response.url); if (!finalUrl || finalUrl.pathname !== url.pathname || finalUrl.search !== url.search) { throw new Error(kind + '响应地址异常,当前阅读已保留'); } } var template = document.createElement('template'); template.innerHTML = await response.text(); return template.content; })(), new Promise(function (_, reject) { timeout = setTimeout(function () { if (controller) controller.abort(); reject(new Error(kind + '加载超时,当前阅读已保留')); }, 20000); })]); } finally { clearTimeout(timeout); if (state.tocController === controller) state.tocController = null; } } function parseCatalogue(doc, pageUrl, cp) { var title = doc.querySelector('title'); if (doc.querySelector('input[name="GOEDGE_WAF_CAPTCHA_CODE"], #loginForm') || (title && /^(?:身份验证|安全验证|访问验证|人机验证|登录\s*[-—]|Just a moment)/i.test(title.textContent.trim()))) { throw new Error('目录需要登录或验证,当前阅读已保留'); } var chapterBox = doc.querySelector('#chapters .direList'); if (!chapterBox) throw new Error('未找到原站章节目录,当前阅读已保留'); var anchors = chapterBox.querySelectorAll('li .name > a[href]'); var chapters = []; var seen = new Set(); for (var i = 0; i < anchors.length; i++) { var url = readUrl(anchors[i].getAttribute('href'), pageUrl.href); if (!url || url.search || seen.has(url.href)) continue; var label = anchors[i].textContent.trim(); if (!label) continue; var order = (cp - 1) * 100 + i + 1; chapters.push({ url: url, label: label, order: order }); seen.add(url.href); state.chapterOrders.set(url.pathname, order); state.chapterTitles.set(url.pathname, cleanChapterTitle(label)); } try { localStorage.setItem(chapterOrderKey, JSON.stringify(Array.from(state.chapterOrders))); } catch (_) {} try { localStorage.setItem(chapterTitleKey, JSON.stringify(Array.from(state.chapterTitles))); } catch (_) {} reconcileProgressOrders(); if (!chapters.length) throw new Error('这一页没有可用章节,当前阅读已保留'); var ranges = {}; ranges[cp] = String((cp - 1) * 100 + 1) + '-' + String((cp - 1) * 100 + chapters.length); var max = cp; var rangeLinks = doc.querySelectorAll('#chapters .page-range-list a[href]'); for (var j = 0; j < rangeLinks.length; j++) { var rangeUrl = siteUrl(rangeLinks[j].getAttribute('href'), pageUrl.href); if (!rangeUrl || rangeUrl.pathname !== '/book/' + bookId + '.html') continue; var page = Number(rangeUrl.searchParams.get('cp')); if (!(page >= 1 && page <= 100 && page % 1 === 0)) continue; ranges[page] = rangeLinks[j].textContent.trim() || String(page); max = Math.max(max, page); } var currentRange = doc.querySelector('#chapters .page-range-list .cur'); if (currentRange) ranges[cp] = currentRange.textContent.trim() || ranges[cp]; return { chapters: chapters, ranges: ranges, max: max }; } function renderCatalogue(data, cp) { if (!state.tocOpen || !state.tocPages || !state.tocList) return; state.tocMax = data.max; state.tocPages.textContent = ''; for (var page = 1; page <= data.max; page++) { var button = document.createElement('button'); button.type = 'button'; button.setAttribute('data-bm-toc-page', String(page)); button.setAttribute('aria-label', '目录 ' + (data.ranges[page] || page)); button.textContent = data.ranges[page] || String(page); button.style.cssText = 'flex:0 0 auto;padding:6px 8px;border:1px solid currentColor;' + 'border-radius:5px;background:none;font-size:12px;'; if (page === cp) { button.setAttribute('aria-current', 'page'); button.style.setProperty('font-weight', '700'); } state.tocPages.appendChild(button); } state.tocList.textContent = ''; data.chapters.forEach(function (chapter) { var button = document.createElement('button'); button.type = 'button'; button.setAttribute('data-bm-toc-url', chapter.url.href); button.textContent = chapter.label; button.style.cssText = 'display:block;width:100%;box-sizing:border-box;padding:11px 10px;' + 'border:0;border-bottom:1px solid rgba(90,80,70,.18);' + 'background:none;text-align:left;font-size:16px;line-height:1.5;'; if (state.first && chapter.url.pathname === state.first.url.pathname) { button.setAttribute('aria-current', 'page'); button.style.setProperty('font-weight', '700'); } state.tocList.appendChild(button); }); setCatalogueStatus(''); applyTheme(currentTheme); } async function loadCatalogue(cp) { if (!state.tocOpen || !(cp >= 1 && cp <= 100 && cp % 1 === 0)) return; stopCatalogueRequest(); state.tocPage = cp; try { localStorage.setItem(tocPageKey, String(cp)); } catch (_) {} var token = ++state.tocSeq; setCatalogueStatus('正在加载原站目录…'); if (state.tocCache.has(cp)) { renderCatalogue(state.tocCache.get(cp), cp); return; } if (state.tocList) state.tocList.textContent = ''; var url = new URL('/book/' + bookId + '.html?cp=' + cp, origin); try { var doc = await fetchInertPage(url, '目录'); var data = parseCatalogue(doc, url, cp); if (!state.tocOpen || token !== state.tocSeq) return; state.tocCache.set(cp, data); renderCatalogue(data, cp); } catch (error) { if (state.tocOpen && token === state.tocSeq) setCatalogueStatus(error.message || '目录加载失败,当前阅读已保留'); } } async function chooseCatalogueChapter(value) { var url = readUrl(value); if (!state.tocOpen || !url || url.search) return; stopCatalogueRequest(); if (state.first && pageKey(state.first.url) === pageKey(url)) { state.reader.scrollTop = 0; closeCatalogue(); saveChapterStart(url); return; } var token = ++state.tocSeq; setCatalogueStatus('正在读取章节…'); try { var doc = await fetchInertPage(url, '本章'); var page = extract(doc, url); if (!state.tocOpen || token !== state.tocSeq) return; showCatalogueChapter(page); } catch (error) { if (state.tocOpen && token === state.tocSeq) setCatalogueStatus(error.message || '本章暂不能打开,当前阅读已保留'); } } function saveChapterStart(url) { state.progressTouched = false; recordProgress({ url: url.href, index: 0, ratio: 0, time: Date.now(), title: titleForProgress(url) }); } function showCatalogueChapter(page, checkpoint) { if (!activeReader() || !state.source) throw new Error('阅读模式已关闭,当前章节未切换'); var target = readUrl(page.url.href); if (!target) throw new Error('章节地址不正确,当前阅读已保留'); try { history.replaceState(history.state, '', target.href); } catch (_) { throw new Error('浏览器无法原位切换地址,当前阅读已保留'); } rememberChapterTitle(page); // 只复制解码后的纯文本;下载页面中的脚本、图片和广告节点都不进入阅读层。 state.readSeq++; if (state.timer) { clearTimeout(state.timer); state.timer = null; } if (state.progressTimer) { clearTimeout(state.progressTimer); state.progressTimer = null; } state.pendingResume = null; try { sessionStorage.removeItem(pendingKey); } catch (_) {} replaceReadingPages(page, []); delete page.content; state.first = page; state.next = page.next; state.pages = []; state.seen = new Set([pageKey(target)]); state.busy = false; state.blocked = false; state.error = ''; markProgressParagraphs(); state.reader.scrollTop = 0; if (state.tocOpen) closeCatalogue(); if (state.progressOpen) closeProgressPanel(); if (checkpoint) { var selected = normalizeProgress(checkpoint); selected.time = Date.now(); selected.title = page.title; recordProgress(selected); state.pendingResume = selected; restorePendingProgress(); } else saveChapterStart(target); updateStatus(); } function replaceReadingPages(page, remaining) { state.source.textContent = ''; state.content.textContent = ''; for (var i = 0; i < page.paragraphs.length; i++) { var paragraph = document.createElement('p'); paragraph.textContent = page.paragraphs[i]; state.source.appendChild(paragraph); state.content.appendChild(paragraph.cloneNode(true)); } state.source.setAttribute('data-bm-page', pageKey(page.url)); state.content.setAttribute('data-bm-page', pageKey(page.url)); remaining.forEach(function (item) { appendPage(state.source, item); appendPage(state.content, item); }); var heading = document.querySelector('.conC h1.title'); if (heading) heading.textContent = page.title; var readerHeading = state.reader.querySelector('.via-reader-header h1'); if (readerHeading) readerHeading.textContent = page.title; document.title = page.docTitle || page.title; var breadcrumb = document.querySelector('.conC .position > span:last-child'); if (breadcrumb) breadcrumb.textContent = page.title; var chapterInfo = document.querySelector('.conC .toolBox > .font14'); if (chapterInfo) chapterInfo.textContent = page.chapterInfo || ''; var staleChapterActions = document.querySelector('.conC .btnErrorW'); if (staleChapterActions) staleChapterActions.remove(); var navigation = document.querySelector('.readPage'); if (navigation) { navigation.textContent = ''; if (page.next) { var next = document.createElement('a'); next.className = 'btnGreen'; next.href = page.next.href; next.textContent = page.next.pathname === page.url.pathname ? '下一页 >' : '下一章 >'; navigation.appendChild(next); } var catalogue = document.createElement('a'); catalogue.className = 'btnBlue'; catalogue.href = '/book/' + bookId + '.html'; catalogue.textContent = '目录'; navigation.appendChild(catalogue); } } function siteUrl(value, base) { try { var url = new URL(value, base || location.href); if (url.protocol === 'https:' && url.origin === origin && !url.username && !url.password) return url; } catch (_) {} return null; } function readUrl(value, base) { var url = siteUrl(value, base); if (!url || !bookId || !new RegExp('^/read/' + bookId + '/\\d+\\.html$').test(url.pathname)) return null; url.hash = ''; return url; } function pageKey(url) { var copy = new URL(url.href); copy.hash = ''; if (copy.searchParams.get('p') === '1') copy.searchParams.delete('p'); if (copy.searchParams.sort) copy.searchParams.sort(); return copy.href; } function normalizeProgress(value) { if (!value || typeof value !== 'object') return null; var url = readUrl(value.url); var index = Number(value.index); var ratio = Number(value.ratio); if (!url || !(index >= 0 && index % 1 === 0) || !(ratio >= 0 && ratio <= 1)) return null; var order = state.chapterOrders.get(url.pathname) || Number(value.order) || 0; return { url: url.href, index: index, ratio: ratio, time: Number(value.time) || 0, title: state.chapterTitles.get(url.pathname) || (typeof value.title === 'string' ? cleanChapterTitle(value.title).slice(0, 120) : '') || titleForProgress(url), order: Number.isInteger(order) && order > 0 && order <= 100000 ? order : 0 }; } function progressPage(url) { var page = Number(url.searchParams.get('p')) || 1; return Number.isInteger(page) && page >= 1 ? page : 1; } function compareWithinChapter(a, b) { var first = readUrl(a.url); var second = readUrl(b.url); if (!first || !second || first.pathname !== second.pathname) return null; var pageDifference = progressPage(first) - progressPage(second); return pageDifference || a.index - b.index || a.ratio - b.ratio; } function sameProgressPosition(a, b) { var first = readUrl(a.url); var second = readUrl(b.url); return !!first && !!second && pageKey(first) === pageKey(second) && a.index === b.index && Math.abs(a.ratio - b.ratio) < .001; } function followsKnownNext(previous, current) { var from = readUrl(previous.url); var to = readUrl(current.url); if (!from || !to) return false; var key = pageKey(from); var wanted = pageKey(to); var visited = new Set(); while (!visited.has(key)) { visited.add(key); key = state.forwardLinks.get(key); if (!key) return false; if (key === wanted) return true; } return false; } function isFurtherProgress(candidate, previous) { if (!previous) return true; var within = compareWithinChapter(candidate, previous); if (within !== null) return within > 0; if (candidate.order && previous.order) return candidate.order > previous.order; return followsKnownNext(previous, candidate); } function persistProgressHistory() { try { localStorage.setItem(historyKey, JSON.stringify(state.progressHistory)); } catch (_) {} } function recordProgress(value, writeLegacy, promote) { var progress = normalizeProgress(value); if (!progress) return; if (writeLegacy !== false) { state.savedProgress = progress; try { localStorage.setItem(progressKey, JSON.stringify(progress)); } catch (_) {} } var recent = state.progressHistory.recent; var path = readUrl(progress.url).pathname; for (var i = 0; i < recent.length; i++) { var old = normalizeProgress(recent[i]); if (!old || readUrl(old.url).pathname !== path) continue; if (compareWithinChapter(old, progress) > 0) { old.time = progress.time; if (!old.order) old.order = progress.order; progress = old; } recent.splice(i, 1); break; } recent.unshift(progress); if (recent.length > 1000) recent.length = 1000; var furthest = normalizeProgress(state.progressHistory.furthest); if (promote !== false && isFurtherProgress(progress, furthest)) state.progressHistory.furthest = progress; persistProgressHistory(); updateResumeButton(); if (state.progressOpen) renderProgressHistory(); } function loadProgressHistory() { try { var stored = JSON.parse(localStorage.getItem(historyKey) || 'null'); if (stored && typeof stored === 'object') { state.progressHistory.furthest = normalizeProgress(stored.furthest); if (Array.isArray(stored.recent)) { state.progressHistory.recent = stored.recent.map(normalizeProgress).filter(Boolean).slice(0, 1000); } } } catch (_) {} var legacy = normalizeProgress(state.savedProgress); if (legacy && !state.progressHistory.recent.some(function (entry) { return sameProgressPosition(entry, legacy) && entry.time >= legacy.time; })) recordProgress(legacy, false); } function reconcileProgressOrders() { var history = state.progressHistory; history.furthest = normalizeProgress(history.furthest); history.recent = history.recent.map(normalizeProgress).filter(Boolean); for (var i = 0; i < history.recent.length; i++) { if ((history.furthest || history.recent[i].order) && isFurtherProgress(history.recent[i], history.furthest)) history.furthest = history.recent[i]; } persistProgressHistory(); if (state.progressOpen) renderProgressHistory(); } function cleanChapterTitle(value) { return String(value || '').trim().replace(/\s*[((](?:第\s*\d+\s*页|\d+\s*\/\s*\d+(?:页)?)[))]\s*$/, ''); } function rememberChapterTitle(page) { if (!page || !page.url || !page.title) return; var title = cleanChapterTitle(page.title); if (title && !state.chapterTitles.get(page.url.pathname)) state.chapterTitles.set(page.url.pathname, title); try { localStorage.setItem(chapterTitleKey, JSON.stringify(Array.from(state.chapterTitles))); } catch (_) {} reconcileProgressOrders(); } function titleForProgress(url) { if (state.chapterTitles.has(url.pathname)) return state.chapterTitles.get(url.pathname); if (state.first && state.first.url.pathname === url.pathname) return cleanChapterTitle(state.first.title); for (var i = 0; i < state.pages.length; i++) { if (state.pages[i].url.pathname === url.pathname) return cleanChapterTitle(state.pages[i].title); } return ''; } function updateResumeButton() { if (!state.toolbar) return; var button = state.toolbar.querySelector('[data-bm-resume]'); if (!button) return; button.disabled = !normalizeProgress(state.progressHistory.furthest) && !state.progressHistory.recent.length; button.style.setProperty('opacity', button.disabled ? '.45' : '1', 'important'); } function markProgressParagraphs() { if (!state.content || !state.first) return; var counts = Object.create(null); var paragraphs = state.content.querySelectorAll('p'); for (var i = 0; i < paragraphs.length; i++) { var paragraph = paragraphs[i]; if (paragraph.hasAttribute('data-bm-native-nav') || paragraph.closest('.readPage, .page2-chapter')) continue; var page = paragraph.closest('[data-bm-page]'); var url = page ? readUrl(page.getAttribute('data-bm-page')) : state.first.url; if (!url) continue; var key = pageKey(url); var index = counts[key] || 0; counts[key] = index + 1; paragraph.setAttribute('data-bm-progress-url', url.href); paragraph.setAttribute('data-bm-progress-index', String(index)); } } function saveProgressNow(allowProgressPanel) { if (!activeReader() || state.tocOpen || (state.progressOpen && allowProgressPanel !== true) || !state.first) return; var paragraphs = state.content.querySelectorAll('p[data-bm-progress-index]'); var anchor = state.reader.getBoundingClientRect().top + Math.min(120, state.reader.clientHeight * .22); var selected = null; var rect = null; for (var i = 0; i < paragraphs.length; i++) { var candidate = paragraphs[i]; if (candidate.hidden || candidate.closest('[hidden], .readPage, .page2-chapter')) continue; var bounds = candidate.getBoundingClientRect(); if (!(bounds.height > 0)) continue; selected = candidate; rect = bounds; if (bounds.bottom > anchor) break; } if (!selected || !rect) return; var url = readUrl(selected.getAttribute('data-bm-progress-url')); var index = Number(selected.getAttribute('data-bm-progress-index')); if (!url || !(index >= 0 && index % 1 === 0)) return; var ratio = Math.max(0, Math.min(1, (anchor - rect.top) / rect.height)); recordProgress({ url: url.href, index: index, ratio: Math.round(ratio * 1000) / 1000, time: Date.now(), title: titleForProgress(url) }); } function scheduleProgress() { if (state.tocOpen || state.progressOpen) return; state.progressTouched = true; if (state.progressTimer) return; state.progressTimer = setTimeout(function () { state.progressTimer = null; saveProgressNow(); compactReadPages(); }, 800); } function restoreProgressHere(progress) { if (!activeReader()) return false; var targetUrl = readUrl(progress.url); if (!targetUrl) return false; var paragraphs = state.content.querySelectorAll('p[data-bm-progress-index]'); for (var i = 0; i < paragraphs.length; i++) { var paragraph = paragraphs[i]; var url = readUrl(paragraph.getAttribute('data-bm-progress-url')); if (!url || pageKey(url) !== pageKey(targetUrl) || Number(paragraph.getAttribute('data-bm-progress-index')) !== progress.index) continue; var rect = paragraph.getBoundingClientRect(); if (!(rect.height > 0)) return false; var anchor = state.reader.getBoundingClientRect().top + Math.min(120, state.reader.clientHeight * .22); state.reader.scrollTop += rect.top + progress.ratio * rect.height - anchor; return true; } return false; } function restorePendingProgress() { var pending = normalizeProgress(state.pendingResume); if (!pending || !state.first || pageKey(readUrl(pending.url)) !== pageKey(state.first.url)) return; var attempts = 0; function attempt() { if (!activeReader()) return; markProgressParagraphs(); if (restoreProgressHere(pending)) { state.pendingResume = null; try { sessionStorage.removeItem(pendingKey); } catch (_) {} saveProgressNow(); } else if (++attempts < 4) setTimeout(attempt, 250); else { state.pendingResume = null; try { sessionStorage.removeItem(pendingKey); } catch (_) {} } } attempt(); } async function chooseHistoryPosition(button) { if (!state.progressOpen) return; var url = readUrl(button.getAttribute('data-bm-progress-url')); var index = Number(button.getAttribute('data-bm-progress-index')); var ratio = Number(button.getAttribute('data-bm-progress-ratio')); if (!url || !(index >= 0 && index % 1 === 0) || !(ratio >= 0 && ratio <= 1)) return; var choices = [state.progressHistory.furthest].concat(state.progressHistory.recent); var progress = null; for (var i = 0; i < choices.length; i++) { var entry = normalizeProgress(choices[i]); if (entry && pageKey(readUrl(entry.url)) === pageKey(url) && entry.index === index && Math.abs(entry.ratio - ratio) < .001) { progress = entry; break; } } if (!progress) return; if (progress.index === 0 && progress.ratio === 0 && state.first && pageKey(state.first.url) === pageKey(url)) { state.reader.scrollTop = 0; closeProgressPanel(); progress.time = Date.now(); recordProgress(progress); return; } if (restoreProgressHere(progress)) { closeProgressPanel(); progress.time = Date.now(); recordProgress(progress); return; } stopCatalogueRequest(); var token = ++state.progressSeq; setProgressStatus('正在打开保存的位置…'); try { var doc = await fetchInertPage(url, '进度'); var page = extract(doc, url); if (!state.progressOpen || token !== state.progressSeq) return; showCatalogueChapter(page, progress); } catch (error) { if (state.progressOpen && token === state.progressSeq) { setProgressStatus(error.message || '暂时无法打开,当前阅读已保留'); } } } // 这三个函数是当前章节“书签后、页码后、页脚”的广告插入入口。 // 与单独的站外保护脚本共存:已有不可改写的保护不再覆盖。 ['C061V4rne', 'ZJo6i4ZXG', 'r2lTyoQWN'].forEach(function (name) { try { Object.defineProperty(window, name, { value: function () {}, writable: false, configurable: false }); } catch (_) {} }); try { Object.defineProperty(window, 'open', { value: function () { return null; }, writable: false, configurable: false }); } catch (_) { try { window.open = function () { return null; }; } catch (ignored) {} } function guard(event) { var target = event.target; if (!target || !target.closest) return; var download = target.closest('a[href]'); if (download && download === state.backupDownloadAnchor && state.backupDownloadUrl && download.getAttribute('href') === state.backupDownloadUrl) { event.stopImmediatePropagation(); return; } var backupField = target.closest('[data-bm-backup-file], [data-bm-backup-text]'); if (backupField) { event.stopImmediatePropagation(); return; } var backupControl = target.closest('[data-bm-backup-export], [data-bm-backup-import], ' + '[data-bm-backup-toggle-text], [data-bm-backup-copy], [data-bm-backup-restore-text]'); if (backupControl) { if (event.type === 'click') { event.preventDefault(); if (backupControl.hasAttribute('data-bm-backup-export')) exportBackup(); else if (backupControl.hasAttribute('data-bm-backup-import')) state.backupFile.click(); else if (backupControl.hasAttribute('data-bm-backup-toggle-text')) toggleBackupText(); else if (backupControl.hasAttribute('data-bm-backup-copy')) copyBackupText(); else if (backupControl.hasAttribute('data-bm-backup-restore-text')) restoreBackupText(); } event.stopImmediatePropagation(); return; } var searchControl = target.closest('.btnSearchM, .searchBox form, .searchBoxM input'); if (searchControl) { if (event.type === 'click') { event.preventDefault(); searchNavigationUntil = Date.now() + 5000; location.assign(searchEntry.href); } event.stopImmediatePropagation(); return; } var readerControl = target.closest('[data-bm-toc-open], [data-bm-toc-close], ' + '[data-bm-toc-page], [data-bm-toc-url], [data-bm-toolbar-collapse], ' + '[data-bm-toolbar-expand], [data-bm-resume], [data-bm-progress-close], ' + '[data-bm-progress-url], [data-bm-reader-exit]'); if (readerControl) { if (event.type === 'click') { event.preventDefault(); if (readerControl.hasAttribute('data-bm-toc-open')) openCatalogue(); else if (readerControl.hasAttribute('data-bm-toc-close')) closeCatalogue(); else if (readerControl.hasAttribute('data-bm-toc-page')) { loadCatalogue(Number(readerControl.getAttribute('data-bm-toc-page'))); } else if (readerControl.hasAttribute('data-bm-toc-url')) { chooseCatalogueChapter(readerControl.getAttribute('data-bm-toc-url')); } else if (readerControl.hasAttribute('data-bm-progress-close')) closeProgressPanel(); else if (readerControl.hasAttribute('data-bm-reader-exit')) exitAssistedReader(); else if (readerControl.hasAttribute('data-bm-progress-url')) chooseHistoryPosition(readerControl); else if (readerControl.hasAttribute('data-bm-toolbar-collapse')) setToolbarCollapsed(true); else if (readerControl.hasAttribute('data-bm-toolbar-expand')) setToolbarCollapsed(false); else if (readerControl.hasAttribute('data-bm-resume')) openProgressPanel(); } event.stopImmediatePropagation(); return; } var fontButton = target.closest('[data-bm-font-step]'); if (fontButton) { if (event.type === 'touchstart') fontTouch.button = fontButton; if (event.type === 'touchend' && fontTouch.button === fontButton) { if (!fontButton.disabled) applyFontSize(fontSize + Number(fontButton.getAttribute('data-bm-font-step'))); fontTouch.at = Date.now(); } if (event.type === 'click') { event.preventDefault(); if (!fontButton.disabled && !(fontTouch.button === fontButton && Date.now() - fontTouch.at < 700)) { applyFontSize(fontSize + Number(fontButton.getAttribute('data-bm-font-step'))); } fontTouch.button = null; } event.stopImmediatePropagation(); return; } var themeButton = target.closest('[data-bm-theme-choice]'); if (themeButton) { if (event.type === 'click' || event.type === 'touchend') { if (event.type === 'click') event.preventDefault(); applyTheme(themeButton.getAttribute('data-bm-theme-choice')); } event.stopImmediatePropagation(); return; } var anchor = target.closest('a[href], a[_href]'); if (anchor && state.reader && state.reader.contains(anchor) && /^\s*目录\s*$/.test(anchor.textContent)) { var indexUrl = siteUrl(anchor.getAttribute('href')); if (indexUrl && indexUrl.pathname === '/book/' + bookId + '.html') { if (event.type === 'click') { event.preventDefault(); openCatalogue(); } event.stopImmediatePropagation(); return; } } // Via 原生阅读的上一页/下一页使用 href="#" 和 _href="实际地址"。 var href = anchor && (anchor.getAttribute('href') || '#'); var placeholder = href && /^javascript:\s*(?:void\s*\(\s*0\s*\)\s*;?|;)$/i.test(href.trim()); if (anchor && ((!placeholder && !siteUrl(href)) || (anchor.hasAttribute('_href') && !siteUrl(anchor.getAttribute('_href'))))) { event.preventDefault(); event.stopImmediatePropagation(); return; } if (target.closest('[data-bm-pager-status]')) event.stopImmediatePropagation(); } ['click', 'auxclick', 'pointerdown', 'mousedown', 'touchstart', 'touchend'].forEach(function (type) { window.addEventListener(type, guard, { capture: true, passive: false }); }); window.addEventListener('submit', function (event) { if (event.target && event.target.matches && event.target.matches('.searchBox form')) { event.preventDefault(); event.stopImmediatePropagation(); searchNavigationUntil = Date.now() + 5000; location.assign(searchEntry.href); return; } if (event.target && event.target.action && !siteUrl(event.target.action)) { event.preventDefault(); event.stopImmediatePropagation(); } }, true); if (window.navigation && window.navigation.addEventListener) { window.navigation.addEventListener('navigate', function (event) { if (event.cancelable && !siteUrl(event.destination.url) && !(state.backupDownloadUrl && event.destination.url === state.backupDownloadUrl) && !intentionalSearchNavigation(event.destination.url)) event.preventDefault(); }); } if (!bookId) { try { localStorage.__via_reader_enabled__ = null; } catch (_) {} var catalogMatch = location.pathname.match(/^\/book\/(\d+)\.html$/); var visitedCp = Number(new URLSearchParams(location.search).get('cp')); if (catalogMatch && visitedCp >= 1 && visitedCp <= 100 && visitedCp % 1 === 0) { try { localStorage.setItem('bm-reader-catalog-page-' + catalogMatch[1], String(visitedCp)); } catch (_) {} } if (catalogMatch) { var rememberBookOrders = function () { var cp = visitedCp >= 1 && visitedCp <= 100 && visitedCp % 1 === 0 ? visitedCp : 1; var key = 'bm-reader-chapter-order-' + catalogMatch[1] + '-v1'; var titleKey = 'bm-reader-chapter-title-' + catalogMatch[1] + '-v1'; var orders = new Map(); var titles = new Map(); try { var stored = JSON.parse(localStorage.getItem(key) || '[]'); if (Array.isArray(stored)) stored.forEach(function (item) { if (Array.isArray(item) && typeof item[0] === 'string' && Number.isInteger(item[1])) { orders.set(item[0], item[1]); } }); } catch (_) {} try { var knownTitles = JSON.parse(localStorage.getItem(titleKey) || '[]'); if (Array.isArray(knownTitles)) knownTitles.forEach(function (item) { if (Array.isArray(item) && typeof item[0] === 'string' && typeof item[1] === 'string') { titles.set(item[0], cleanChapterTitle(item[1])); } }); } catch (_) {} var links = document.querySelectorAll('#chapters .direList li .name > a[href]'); for (var i = 0; i < links.length; i++) { var chapter = siteUrl(links[i].getAttribute('href')); if (chapter && new RegExp('^/read/' + catalogMatch[1] + '/\\d+\\.html$').test(chapter.pathname) && !chapter.search) { orders.set(chapter.pathname, (cp - 1) * 100 + i + 1); titles.set(chapter.pathname, cleanChapterTitle(links[i].textContent)); } } if (links.length) try { localStorage.setItem(key, JSON.stringify(Array.from(orders))); } catch (_) {} if (links.length) try { localStorage.setItem(titleKey, JSON.stringify(Array.from(titles))); } catch (_) {} }; if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', rememberBookOrders, { once: true }); else rememberBookOrders(); } return; } function decode(value) { var raw = atob(value); var bytes = new Uint8Array(raw.length); for (var i = 0; i < raw.length; i++) bytes[i] = raw.charCodeAt(i) ^ ((i % 127) + 1); if (typeof TextDecoder === 'function') return new TextDecoder('utf-8', { fatal: true }).decode(bytes); var percent = ''; for (var j = 0; j < bytes.length; j++) percent += '%' + ('0' + bytes[j].toString(16)).slice(-2); return decodeURIComponent(percent); } function hidden(node, boundary) { for (var el = node; el && el !== boundary; el = el.parentElement) { var style = (el.getAttribute('style') || '').replace(/\s/g, '').toLowerCase(); if (el.hidden || el.getAttribute('aria-hidden') === 'true' || el.classList.contains('honeypot') || /(?:display:none|visibility:hidden|opacity:0(?:;|$)|font-size:0(?:px)?(?:;|$))/.test(style)) return true; } return false; } function isChapterArtifact(text) { // 只过滤整段残留的空调用;正常正文中的英文 chapter 或引号不会受影响。 return /^\s*chapter_\s*\(\s*\)\s*;?\s*$/i.test(text); } function extract(doc, url) { var title = doc.querySelector('title'); var docTitle = doc.title || (title ? title.textContent : ''); if (doc.querySelector('input[name="GOEDGE_WAF_CAPTCHA_CODE"], #loginForm') || /^(?:身份验证|安全验证|访问验证|人机验证|登录\s*[-—]|Just a moment)/i.test(docTitle.trim())) { throw new Error('下一页需要验证码或登录,自动接续已停止'); } var content = doc.querySelector('.conC .content'); if (!content) throw new Error('未找到下一页正文,自动接续已停止'); var nodes = content.querySelectorAll('p'); var paragraphs = []; for (var i = 0; i < nodes.length; i++) { if (hidden(nodes[i], content)) continue; var text = nodes[i].textContent; if (nodes[i].hasAttribute('data-obf')) { try { text = decode(nodes[i].getAttribute('data-obf')); } catch (_) { throw new Error('正文解码失败,自动接续已停止'); } } if (text && text.trim() && !isChapterArtifact(text)) paragraphs.push(text.trim()); } if (!paragraphs.length) throw new Error('下一页没有可读取的正文,自动接续已停止'); var heading = doc.querySelector('.conC h1.title'); var links = doc.querySelectorAll('.readPage a[href]'); var next = null; // 有章内分页时优先下一页,避免网站同时提供下一章而跳过本章后半页。 for (var kind = 0; kind < 2 && !next; kind++) { var pattern = kind === 0 ? /^下一页/ : /^下一章/; for (var j = 0; j < links.length; j++) { if (!pattern.test(links[j].textContent.trim())) continue; next = readUrl(links[j].getAttribute('href'), url.href); if (!next) throw new Error('下一页地址不属于本站这本书,自动接续已停止'); break; } } var chapterInfo = doc.querySelector('.conC .toolBox > .font14'); return { url: url, title: heading ? heading.textContent.trim() : docTitle, docTitle: docTitle, chapterInfo: chapterInfo ? chapterInfo.textContent.trim() : '', paragraphs: paragraphs, next: next, content: content }; } function hasPage(target, url) { var wanted = pageKey(url); if (target.getAttribute('data-bm-page') === wanted) return true; var nodes = target.querySelectorAll('[data-bm-page]'); for (var i = 0; i < nodes.length; i++) if (nodes[i].getAttribute('data-bm-page') === wanted) return true; return false; } function appendPage(target, page) { if (!target || hasPage(target, page.url)) return; var section = document.createElement('section'); section.setAttribute('data-bm-page', pageKey(page.url)); if (page.chapterStart) { var title = document.createElement('h2'); title.textContent = page.title; section.appendChild(title); } page.paragraphs.forEach(function (text) { var paragraph = document.createElement('p'); paragraph.textContent = text; section.appendChild(paragraph); }); target.appendChild(section); } // 只保留当前阅读附近的正文窗口;进度/目录仍能重新打开已经释放的章节。 // 布局尚不可测量或读者正在回看前文时,宁可延后,也不删掉可见文字。 function compactReadPages() { if (state.compacting || state.busy || state.tocOpen || state.progressOpen || document.hidden || !activeReader() || !state.first || state.pages.length + 1 <= 12) return; var pages = [state.first].concat(state.pages); var paragraphs = state.content.querySelectorAll('p[data-bm-progress-index]'); var viewport = state.reader.getBoundingClientRect(); var height = state.reader.clientHeight; if (!(height > 0) || !Number.isFinite(viewport.top)) return; var anchorY = viewport.top + Math.min(120, height * .22); var visible = null; var bounds = null; var starts = new Map(); for (var i = 0; i < paragraphs.length; i++) { var paragraph = paragraphs[i]; var rect = paragraph.getBoundingClientRect(); var url = readUrl(paragraph.getAttribute('data-bm-progress-url')); if (!url || !(rect.height > 0) || !Number.isFinite(rect.top) || !Number.isFinite(rect.bottom)) continue; var key = pageKey(url); if (!starts.has(key)) starts.set(key, rect.top); if (!visible && rect.bottom > anchorY && rect.top < viewport.top + height) { visible = paragraph; bounds = rect; } } if (!visible) return; var visibleKey = pageKey(readUrl(visible.getAttribute('data-bm-progress-url'))); var activeIndex = pages.findIndex(function (page) { return pageKey(page.url) === visibleKey; }); var cut = Math.min(pages.length - 8, activeIndex - 2); while (cut > 0 && !(starts.has(pageKey(pages[cut].url)) && starts.get(pageKey(pages[cut].url)) <= viewport.top - 64)) cut--; if (!(cut > 0)) return; var index = visible.getAttribute('data-bm-progress-index'); var retained = pages.slice(cut); // 关闭再开启原生阅读会重新抽取源正文,因此源页面也必须同步收窄。 try { history.replaceState(history.state, '', retained[0].url.href); } catch (_) { return; } state.compacting = true; try { saveProgressNow(); replaceReadingPages(retained[0], retained.slice(1)); delete retained[0].content; state.first = retained[0]; state.pages = retained.slice(1); state.compactedPages += cut; markProgressParagraphs(); var updated = state.content.querySelectorAll('p[data-bm-progress-index]'); for (var j = 0; j < updated.length; j++) { if (updated[j].getAttribute('data-bm-progress-url') !== visible.getAttribute('data-bm-progress-url') || updated[j].getAttribute('data-bm-progress-index') !== index) continue; var after = updated[j].getBoundingClientRect(); if (after.height > 0 && Number.isFinite(after.top)) state.reader.scrollTop += after.top - bounds.top; break; } if (state.progressPanel) { var note = state.progressPanel.querySelector('[data-bm-memory-note]'); if (note) note.hidden = false; } } finally { state.compacting = false; } } function hideReaderNavigation(reader, content) { var metadata = reader.querySelector('.via-reader-header > div'); if (metadata) metadata.remove(); var siteNav = content.querySelectorAll('.readPage, .page2-chapter'); for (var i = 0; i < siteNav.length; i++) siteNav[i].remove(); // Via 自己在正文末尾附上一组目录/上一页/下一页链接;自动接续和顶部目录 // 已接管这些功能,因此直接从正文移除,避免朗读或正文识别再次读到它们。 var paragraphs = content.querySelectorAll('p'); for (var j = 0; j < paragraphs.length; j++) { var paragraph = paragraphs[j]; if (!paragraph.querySelector('a[_href], a[href*="/book/"]')) continue; var text = paragraph.textContent.replace(/[\s||·•]/g, ''); if (!/^(?:(?:上一|下一)(?:页|章)|目录)+$/.test(text)) continue; if (paragraph.nextElementSibling && paragraph.nextElementSibling.tagName === 'BR') { paragraph.nextElementSibling.remove(); } paragraph.remove(); } } function updateStatus() { if (!state.status) return; var message = state.blocked ? state.error : state.busy ? '正在接续下一页…' : ''; if (state.status.getAttribute('data-message') === message) return; state.status.setAttribute('data-message', message); state.status.textContent = message; state.status.hidden = !message; if (state.blocked && state.next) { var manual = document.createElement('a'); manual.href = state.next.href; manual.textContent = '打开该页手动处理'; state.status.appendChild(document.createTextNode(' ')); state.status.appendChild(manual); } } function halt(message) { state.blocked = true; state.error = message; if (state.timer) { clearTimeout(state.timer); state.timer = null; } updateStatus(); } function activeReader() { if (!state.reader || !state.reader.isConnected || !state.content || !state.content.isConnected || state.reader.hidden) return false; var style = window.getComputedStyle(state.reader); return style.display !== 'none' && style.visibility !== 'hidden' && style.visibility !== 'collapse'; } function nearEnd() { if (!activeReader() || document.hidden || state.tocOpen || state.progressOpen) return false; var height = state.reader.clientHeight; if (!(height > 0 && state.reader.scrollHeight >= height)) return false; return state.reader.scrollHeight - state.reader.scrollTop - height <= Math.min(350, height * 0.6); } function schedule() { if (state.timer || state.busy || state.blocked || !state.next || !nearEnd()) return; state.timer = setTimeout(function () { state.timer = null; if (nearEnd()) loadNext(); }, Math.max(250, 2000 - (Date.now() - state.lastRequest))); } async function loadNext() { if (state.busy || state.blocked || !state.next || !nearEnd()) return; var readSeq = state.readSeq; var url = readUrl(state.next.href); if (!url) { halt('下一页地址不属于本站这本书,自动接续已停止'); return; } if (state.seen.has(pageKey(url))) { halt('下一页链接重复,自动接续已停止'); return; } state.busy = true; state.lastRequest = Date.now(); updateStatus(); var controller = typeof AbortController === 'function' ? new AbortController() : null; var timeout; try { var operation = (async function () { var response = await fetch(url.href, { credentials: 'same-origin', redirect: 'manual', signal: controller ? controller.signal : undefined }); if (response.type === 'opaqueredirect' || (response.status >= 300 && response.status < 400)) { throw new Error('下一页要求跳转,可能需要验证码或登录,自动接续已停止'); } if (!response.ok) throw new Error('下一页请求失败(' + response.status + '),自动接续已停止'); if (response.url) { var finalUrl = readUrl(response.url); if (!finalUrl || pageKey(finalUrl) !== pageKey(url)) throw new Error('下一页响应地址异常,自动接续已停止'); } var html = await response.text(); // template 是惰性文档:后页的脚本、图片与 iframe 不执行、不请求。 var template = document.createElement('template'); template.innerHTML = html; return extract(template.content, url); })(); var page = await Promise.race([operation, new Promise(function (_, reject) { timeout = setTimeout(function () { if (controller) controller.abort(); reject(new Error('下一页网络超时,自动接续已停止')); }, 20000); })]); if (readSeq !== state.readSeq) return; var previous = state.pages.length ? state.pages[state.pages.length - 1].url : state.first.url; state.forwardLinks.set(pageKey(previous), pageKey(page.url)); if (previous.pathname !== page.url.pathname && state.chapterOrders.has(previous.pathname) && !state.chapterOrders.has(page.url.pathname)) { state.chapterOrders.set(page.url.pathname, state.chapterOrders.get(previous.pathname) + 1); try { localStorage.setItem(chapterOrderKey, JSON.stringify(Array.from(state.chapterOrders))); } catch (_) {} } page.chapterStart = previous.pathname !== page.url.pathname; rememberChapterTitle(page); delete page.content; state.pages.push(page); state.seen.add(pageKey(page.url)); state.next = page.next; appendPage(state.source, page); if (activeReader()) { appendPage(state.content, page); markProgressParagraphs(); } } catch (error) { if (readSeq === state.readSeq) { halt(error.name === 'AbortError' ? '下一页网络超时,自动接续已停止' : error.message || '自动接续失败'); } } finally { clearTimeout(timeout); if (readSeq === state.readSeq) { state.busy = false; updateStatus(); compactReadPages(); } // 等下一次读近底部的滚动,不在一次操作后递归预抓整本书。 } } function bindReader() { var reader = document.querySelector('.via-reader-body'); var content = reader && reader.querySelector('.via-reader-content'); if (reader && content) { state.autoEntryDone = true; if (state.autoEntryTimer) { clearTimeout(state.autoEntryTimer); state.autoEntryTimer = null; } } if (!state.source || !reader || !content) { if (state.reader) { state.reader.removeEventListener('scroll', schedule); state.reader.removeEventListener('scroll', scheduleProgress); } state.reader = state.content = state.status = state.paper = state.toolbar = state.toolbarHandle = null; state.tocPanel = state.tocList = state.tocPages = state.tocStatus = null; state.tocOpen = false; state.tocSeq++; state.progressPanel = state.progressList = state.progressStatus = null; state.progressOpen = false; state.progressSeq++; stopCatalogueRequest(); if (state.timer) { clearTimeout(state.timer); state.timer = null; } if (state.progressTimer) { clearTimeout(state.progressTimer); state.progressTimer = null; } return; } if (reader === state.reader && content === state.content) return; if (state.reader) { state.reader.removeEventListener('scroll', schedule); state.reader.removeEventListener('scroll', scheduleProgress); } state.reader = reader; state.content = content; state.progressTouched = false; installThemeControls(reader); hideReaderNavigation(reader, content); state.pages.forEach(function (page) { appendPage(state.source, page); appendPage(content, page); }); markProgressParagraphs(); recordProgress({ url: state.first.url.href, index: 0, ratio: 0, time: Date.now(), title: state.first.title }, false, false); // 状态行在正文外,不改变阅读界面,也不混进下一次 Readability 正文抽取。 var status = document.createElement('div'); status.setAttribute('data-bm-pager-status', ''); status.setAttribute('role', 'status'); status.style.cssText = 'font-size:.85em;line-height:1.8;margin:12px 16px 24px;'; status.hidden = true; content.parentElement.appendChild(status); state.status = status; reader.addEventListener('scroll', schedule, { passive: true }); reader.addEventListener('scroll', scheduleProgress, { passive: true }); restorePendingProgress(); updateStatus(); schedule(); } function start() { var initial = readUrl(location.href); var first; try { first = extract(document, initial); } catch (_) { try { localStorage.__via_reader_enabled__ = null; } catch (ignored) {} return; } state.source = first.content; state.first = first; state.next = first.next; rememberChapterTitle(first); installReaderStyle(); state.source.setAttribute('data-bm-page', pageKey(initial)); state.seen.add(pageKey(initial)); // 原节点保留,只把网站编码的文字还原,供 Via 自身 Readability 抽取。 var nodes = state.source.querySelectorAll('p[data-obf]'); for (var i = 0; i < nodes.length; i++) { if (!hidden(nodes[i], state.source)) nodes[i].textContent = decode(nodes[i].getAttribute('data-obf')); } var sourceParagraphs = state.source.querySelectorAll('p'); for (var j = 0; j < sourceParagraphs.length; j++) { if (isChapterArtifact(sourceParagraphs[j].textContent)) sourceParagraphs[j].remove(); } // 只有完整章节正文请求 Via 自动开启;原生阅读脚本打开后会清除标记。 if (!document.querySelector('.via-reader-body') && document.querySelector('.conC h1.title') && document.querySelector('.readPage')) { try { localStorage.__via_reader_enabled__ = '1'; } catch (_) {} requestAutoReader(); } new MutationObserver(bindReader).observe(document.body, { childList: true, subtree: true }); window.addEventListener('resize', schedule, { passive: true }); document.addEventListener('visibilitychange', function () { if (document.hidden && (state.progressTouched || !normalizeProgress(state.savedProgress))) saveProgressNow(); else schedule(); }); window.addEventListener('pagehide', function () { if (state.progressTouched || !normalizeProgress(state.savedProgress)) saveProgressNow(); }); bindReader(); } function requestAutoReader() { if (state.autoEntryDone || state.autoEntryTimer) return; state.autoEntryTimer = setTimeout(function () { state.autoEntryTimer = null; if (state.autoEntryDone || !state.first || !document.body) return; state.autoEntryDone = true; if (document.querySelector('.via-reader-body')) { bindReader(); return; } var reader = document.createElement('div'); reader.className = 'via-reader-body'; reader.setAttribute('data-bm-auto-reader', ''); var frame = document.createElement('div'); frame.style.cssText = 'width:100%;box-sizing:border-box;font-size:' + fontSize + 'px;'; var header = document.createElement('div'); header.className = 'via-reader-header'; var title = document.createElement('h1'); title.textContent = state.first.title; header.appendChild(title); frame.appendChild(header); var content = document.createElement('div'); content.className = 'via-reader-content'; state.first.paragraphs.forEach(function (text) { var paragraph = document.createElement('p'); paragraph.textContent = text; content.appendChild(paragraph); }); frame.appendChild(content); reader.appendChild(frame); var key = 'via-reader-data'; if (!document.body.hasAttribute(key)) document.body.setAttribute(key, document.body.style.overflow); document.body.style.overflow = 'hidden'; var viewport = document.querySelector('meta[name="viewport"]'); if (viewport && !viewport.hasAttribute(key)) { viewport.setAttribute(key, viewport.getAttribute('content') || ''); viewport.setAttribute('content', 'width=device-width'); } try { localStorage.__via_reader_enabled__ = null; } catch (_) {} document.body.appendChild(reader); bindReader(); }, 500); } function exitAssistedReader() { var reader = state.reader; if (!reader || !reader.hasAttribute('data-bm-auto-reader')) return; if (state.progressOpen) closeProgressPanel(); saveProgressNow(); state.autoEntryDone = true; if (state.autoEntryTimer) { clearTimeout(state.autoEntryTimer); state.autoEntryTimer = null; } var key = 'via-reader-data'; if (document.body.hasAttribute(key)) { document.body.style.overflow = document.body.getAttribute(key); document.body.removeAttribute(key); } var viewport = document.querySelector('meta[name="viewport"]'); if (viewport && viewport.hasAttribute(key)) { viewport.setAttribute('content', viewport.getAttribute(key)); viewport.removeAttribute(key); } reader.remove(); bindReader(); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start, { once: true }); else start(); })();