// ==UserScript== // @name 笔趣阁外观优化 // @namespace https://gitee.com/linhq1999/OhMyScript // @version 1.9 // @description 专注阅读 // @author LinHQ // @match https://www.shuquge.com/txt/* // @match https://www.sywx8.com/* // @grant GM_addStyle // @grant GM_xmlhttpRequest // @inject-into auto // @downloadURL none // ==/UserScript== 'use strict'; (function () { var configs = { "shuquge": { "main": "div.reader", "title": ".reader h1", "txt": "#content", "toc": "dd a", "tocJump": 12, "filter": ["div.header", "div.nav", "div.link"], "txtfilter": ["shuqu"] /*带有此关键字的行将被删除*/ }, "sywx": { "main": "div#container", "title": "div>h1", "toc": "li a", "tocJump": 0, "txt": "div#BookText", "filter": ["div.top", ".link.xb", "#footer"], "txtfilter": ["最快更新", "松语"] /*带有此关键字的行将被删除*/ }, "style": "\n body {\n background-color: #EAEAEF !important;\n }\n\n .bqg.inject.win {\n width: 50% !important;\n min-width: 600px;\n border: 2px double gray !important;\n border-radius: 8px;\n }\n\n .bqg.inject.txt {\n font-family: '\u6977\u4F53'!important;\n background-color: #EAEAEF !important;\n padding: 0 10px 0 20px !important;\n }\n\n .bqg.inject.title {\n color: black;\n background-color: #EAEAEF;\n font-family: '\u6977\u4F53';\n }\n\n .hq.inject.toc {\n width: 270px;\n position: fixed;\n top: 30px;\n padding: 5px;\n display: flex;\n flex-flow: column;\n transition: left 0.5s; \n }\n\n .hq.inject ul {\n max-height: 280px;\n /*offsetTop \u8BA1\u7B97\u9700\u8981*/\n position:relative;\n overflow: auto;\n }\n\n .hq.inject ul li {\n cursor: pointer;\n background: #e1e1e1;\n margin: 2px;\n width: 90%;\n padding: 1px 1.5px;\n font-size: 0.9rem;\n font-weight: bold;\n border-radius: 2px;\n }\n\n .hq.inject ul li:hover {\n background: #EAEAEF;\n }\n\n .hq.inject.toc>div {\n height: 20px;\n width: 20px;\n border-radius: 4px;\n background: red;\n align-self: end;\n cursor: pointer;\n margin: 4px 0;\n }\n " }; var lineHeight = 1.3; // 查询已经保存的字体信息 var oldPerCfg = localStorage.getItem("bqg_cfg"); var defaultPerCfg = { "fontSize": 16, "lineHeight": 16 * lineHeight, "viewMode": "unset" }; // 检查是否存在已有设置且和当前版本相符 var perCfg; if (oldPerCfg !== null) { var cfg_1 = JSON.parse(oldPerCfg); if (Object.keys(cfg_1).length === Object.keys(defaultPerCfg).length) { perCfg = cfg_1; } else { perCfg = defaultPerCfg; } } // 检测当前的网址,应用对应的设置 var cfg; if (document.URL.includes("shuqu")) { cfg = configs.shuquge; } else { cfg = configs.sywx; } GM_addStyle(configs.style); var doInject = function () { var _a, _b; // 执行过滤 cfg.filter.forEach(function (filter) { var _a; return (_a = document.querySelectorAll(filter)) === null || _a === void 0 ? void 0 : _a.forEach(function (ele) { return ele.remove(); }); }); var textWin = document.querySelector(cfg.txt); textWin.setAttribute("style", "font-size:" + perCfg.fontSize + "px;line-height:" + perCfg.lineHeight + "px"); textWin.classList.add("bqg", "inject", "txt"); // 执行文字过滤 if (cfg.txtfilter !== undefined) { textWin.innerText = (_b = (_a = textWin.innerText) === null || _a === void 0 ? void 0 : _a.split("\n\n")) === null || _b === void 0 ? void 0 : _b.filter(function (line) { for (var _i = 0, _a = cfg.txtfilter; _i < _a.length; _i++) { var key = _a[_i]; if (line.includes(key)) { return false; } } return true; }).join("\n\n"); } var saveFontCfg = function () { perCfg.lineHeight = perCfg.fontSize * lineHeight; textWin.style.lineHeight = perCfg.lineHeight + "px"; localStorage.setItem("bqg_cfg", JSON.stringify(perCfg)); }; var mainWin = document.querySelector(cfg.main); mainWin.classList.add("bqg", "inject", "win"); // 切换视图 mainWin.style.height = perCfg.viewMode; // 检测滚动主体,不同的视图滚动主体不一样 var scroller = (perCfg.viewMode.includes("vh")) ? mainWin : window; // 检测滚动比例 var modifier = (perCfg.viewMode.includes("vh")) ? 0.9 : 1; var title = document.querySelector(cfg.title); title.classList.add("bqg", "inject", "title"); document.onclick = function (ev) { // 下半屏单击下滚,反之上滚 var direct = (ev.clientY - window.innerHeight / 2 > 0) ? 1 : -1; scroller.scrollBy({ top: (window.innerHeight * modifier - lineHeight) * direct }); }; document.body.onkeydown = function (ev) { var _a, _b; switch (ev.key) { case "-": perCfg.fontSize -= 2; textWin.style.fontSize = perCfg.fontSize + "px"; saveFontCfg(); break; case "=": perCfg.fontSize += 2; textWin.style.fontSize = perCfg.fontSize + "px"; saveFontCfg(); break; case "o": perCfg.viewMode = (perCfg.viewMode.includes("vh")) ? "unset" : "90vh"; scroller = (perCfg.viewMode.includes("vh")) ? mainWin : window; mainWin.style.height = perCfg.viewMode; modifier = (perCfg.viewMode.includes("vh")) ? 0.9 : 1; saveFontCfg(); break; case "j": scroller.scrollBy({ top: window.innerHeight * modifier - perCfg.lineHeight }); break; case "k": scroller.scrollBy({ top: window.innerHeight * -1 * modifier + perCfg.lineHeight }); break; case "h": var prevs = document.querySelectorAll("a"); for (var _i = 0, prevs_1 = prevs; _i < prevs_1.length; _i++) { var prev = prevs_1[_i]; if ((_a = prev.textContent) === null || _a === void 0 ? void 0 : _a.includes("上一")) { prev.click(); break; } } break; case "l": var nexts = document.querySelectorAll("a"); for (var _c = 0, nexts_1 = nexts; _c < nexts_1.length; _c++) { var next = nexts_1[_c]; if ((_b = next.textContent) === null || _b === void 0 ? void 0 : _b.includes("下一")) { next.click(); break; } } break; case "t": // 目录初始状态 var toc_1 = document.querySelector(".hq.inject.toc"); if (parseInt(toc_1.style.left) < 0) { toc_1.style.left = "15px"; } else { toc_1.style.left = "-300px"; } default: break; } }; }; // 先调用一次,后面是有变化时才会触发,避免有时无法起作用 doInject(); // 强力覆盖 new MutationObserver(function (_, ob) { doInject(); }).observe(document.body, { childList: true }); // 添加目录 var toc = document.createElement("div"); toc.className = "hq inject toc"; toc.onclick = function (ev) { return ev.stopPropagation(); }; toc.style.left = "-300px"; document.body.append(toc); // 目录状态指示灯 var pointer = document.createElement("div"); pointer.title = "单击以刷新目录缓存"; toc.append(pointer); // 目录列表 var ul = document.createElement("ul"); toc.append(ul); // fetchTOC 获取目录信息并重新渲染 var fetchTOC = function (currentBookLink, pointer) { GM_xmlhttpRequest({ url: currentBookLink, // 直接返回 dom responseType: "document", onload: function (resp) { var _a, _b; var doc = resp.response; var tocs = doc.querySelectorAll(cfg.toc); var data = []; // 序列化存储准备 for (var _i = 0, tocs_1 = tocs; _i < tocs_1.length; _i++) { var link = tocs_1[_i]; data.push({ "title": (_a = link.textContent) !== null && _a !== void 0 ? _a : "", "href": (_b = link.href) !== null && _b !== void 0 ? _b : "" }); } if (cfg.tocJump) data = data.slice(cfg.tocJump + 1); // 缓存目录信息 sessionStorage.setItem(currentBookLink, JSON.stringify(data)); renderToc(data, ul); pointer.style.backgroundColor = "green"; }, onprogress: function (_) { return pointer.style.backgroundColor = "yellow"; }, onerror: function (_) { return pointer.style.backgroundColor = "red"; } }); }; var renderToc = function (toc, ul) { // 清空旧内容 ul.innerHTML = ""; var current = null; var _loop_1 = function (lnk) { var li = document.createElement("li"); li.textContent = lnk.title; if (current == null && document.URL == lnk.href) { current = li; } li.onclick = function (ev) { document.location.href = lnk.href; ev.stopPropagation(); }; ul.append(li); }; for (var _i = 0, toc_2 = toc; _i < toc_2.length; _i++) { var lnk = toc_2[_i]; _loop_1(lnk); } // 滚动到当前位置,并高亮 current === null || current === void 0 ? void 0 : current.setAttribute("style", "background: #EAEAEF;color: #1E90FF"); ul.scrollTo({ top: (current === null || current === void 0 ? void 0 : current.offsetTop) - 140 }); }; var source = document.URL.split("/"); source.pop(); // 最后加斜杠保险 var currentBook = source.join("/") + "/"; var currentBookToc = sessionStorage.getItem(currentBook); if (currentBookToc === null) { fetchTOC(currentBook, pointer); } else { pointer.style.background = "green"; renderToc(JSON.parse(currentBookToc), ul); } // 单击指示灯刷新目录缓存 pointer.onclick = function () { return fetchTOC(currentBook, pointer); }; })();