// ==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
// ==/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); };
})();