您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
轻松跳转小说章节
// ==UserScript== // @name NovelJump // @name:zh 小说章节跳转 // @namespace https://github.com/SuniRein/scripts // @version 1.1.0 // @description 轻松跳转小说章节 // @author SuniRein // @match https://www.linovelib.com/* // @grant none // @icon https://www.google.com/s2/favicons?sz=64&domain=linovelib.com // @license GPL3 // @supportURL https://github.com/SuniRein/scripts/blob/main/CHANGELOG.md // ==/UserScript== (function () { 'use strict'; function getCurrentUrlInfo() { const match = location.pathname.match(/\/novel\/(\d+)\/(\d+)(?:_(\d+))?\.html/); if (!match) { console.error('[NovelJump] 当前页面 URL 格式不符合预期'); return null; } return { novelId: parseInt(match[1], 10), chapterId: parseInt(match[2], 10), sectionId: match[3] ? parseInt(match[3], 10) : 1, }; } function generateUrl(novelId, chapterId, sectionId) { return `/novel/${novelId}/${chapterId}${sectionId > 1 ? '_' + sectionId : ''}.html`; } function jump(novelId, chapterId, sectionId) { if (chapterId < 1) { console.warn('[NovelJump] 无效的章节编号: ', chapterId); return; } if (sectionId < 1) { console.warn('[NovelJump] 无效的节偏移值'); return; } window.location.href = generateUrl(novelId, chapterId, sectionId); } function getFinalSectionId(info) { if (info.sectionId == 1) { console.log('[NovelJump] 当前章节为第一节,无法获取最后一节 ID'); return null; } const title = document.getElementsByTagName('h1')[0].textContent; const finalSectionIdStr = title.match(/((\d+)\/(\d+))/)[2]; const finalSectionId = parseInt(finalSectionIdStr, 10); console.log('[NovelJump] 成功获取最后一节 ID'); return finalSectionId; } // 创建悬浮框并添加到页面 function createFloatingPanel(info) { const { novelId, chapterId, sectionId } = info; const panel = document.createElement('div'); panel.id = 'chapter-nav-box'; panel.style.position = 'fixed'; panel.style.top = '50%'; panel.style.right = '10px'; panel.style.transform = 'translateY(-50%)'; panel.style.backgroundColor = 'rgba(255, 255, 255, 0.95)'; panel.style.border = '1px solid #ccc'; panel.style.borderRadius = '8px'; panel.style.padding = '10px'; panel.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.15)'; panel.style.zIndex = '9999'; panel.style.fontFamily = 'sans-serif'; panel.style.fontSize = '14px'; panel.style.width = '90px'; const prevBtn = document.createElement('button'); prevBtn.textContent = '上一章'; prevBtn.onclick = () => jump(novelId, chapterId - 1, 1); const nextBtn = document.createElement('button'); nextBtn.textContent = '下一章'; nextBtn.onclick = () => jump(novelId, chapterId + 1, 1); const input = document.createElement('input'); input.type = 'number'; input.min = '1'; input.placeholder = '节号'; input.id = 'section-input'; input.style.width = '100%'; input.style.marginTop = '6px'; input.style.boxSizing = 'border-box'; input.value = sectionId + 1; // 自动填充下一节 const goBtn = document.createElement('button'); goBtn.textContent = '跳转节'; goBtn.onclick = () => { const sectionInput = document.getElementById('section-input'); const section = parseInt(sectionInput.value, 10); if (isNaN(section) || section <= 0) { alert('请输入有效的节号(正整数)!'); return; } jump(novelId, chapterId, section); }; let elements = [prevBtn, nextBtn, input, goBtn]; let finalSectionId = getFinalSectionId(info); if (finalSectionId) { const lastBtn = document.createElement('button'); lastBtn.textContent = '最后一节'; lastBtn.onclick = () => jump(novelId, chapterId, finalSectionId); elements.push(lastBtn); } elements.forEach((el) => { el.style.display = 'block'; el.style.margin = '4px 0'; el.style.width = '100%'; el.style.padding = '6px'; if (el.tagName === 'BUTTON') { el.style.backgroundColor = '#409eff'; el.style.color = '#fff'; el.style.border = 'none'; el.style.borderRadius = '4px'; el.style.cursor = 'pointer'; el.onmouseenter = () => (el.style.backgroundColor = '#66b1ff'); el.onmouseleave = () => (el.style.backgroundColor = '#409eff'); } panel.appendChild(el); }); document.body.appendChild(panel); } console.log('[NovelJump] 解析页面信息'); const info = getCurrentUrlInfo(); console.debug('[NovelJump] 当前页面信息:', info); function waitForBodyAndInit() { const checkInterval = setInterval(() => { if (document.body) { clearInterval(checkInterval); createFloatingPanel(info); console.log('[NovelJump] 脚本加载完成'); } }, 100); } waitForBodyAndInit(); })();