Greasy Fork

Greasy Fork is available in English.

笔趣阁外观优化

专注阅读

当前为 2021-11-13 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         笔趣阁外观优化
// @namespace    https://gitee.com/linhq1999/OhMyScript
// @version      2.8
// @description  专注阅读
// @author       LinHQ
// @match        http*://www.shuquge.com/*.html
// @exclude      http*://www.shuquge.com/*index.html
// @match        http*://www.sywx8.com/*.html
// @match        http*://www.biqugetv.com/*.html
// @match        http*://www.bqxs520.com/*.html
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @inject-into auto
// @license MIT
// ==/UserScript==
'use strict';
/** 配置示例
* "sites": [
*   {
*       "desc": "shuquge", 网站链接关键字
*       "main": "div.reader", 主要部分选择器
*       "title": ".reader h1", 标题选择器
*       "txt": "#content", 文字部分选择器
*       "toc": "dd a", 目录链接选择器
*       "tocJump": 12, 跳过前面多少章
*       "filter": ["div.header", "div.nav", "div.link"], 带有此选择器的元素将被删除
*       "txtfilter": ["shuqu"] 带有此关键字的行将被删除
*   }
* ]
*/
(function () {
    var lineHeight = 1.3;
    var configs = {
        "sites": [
            {
                "desc": "shuquge",
                "main": "div.reader",
                "title": ".reader h1",
                "txt": "#content",
                "toc": "dd a",
                "tocJump": 12,
                "filter": ["div.header", "div.nav", "div.link"],
                "txtfilter": ["shuqu"] /*带有此关键字的行将被删除*/
            },
            {
                "desc": "sywx",
                "main": "div#container",
                "title": "div>h1",
                "toc": "li a",
                "tocJump": 0,
                "txt": "div#BookText",
                "filter": ["div.top", ".link.xb", "#footer"],
                "txtfilter": ["最快更新", "松语"]
            },
            {
                "desc": "bqxs",
                "main": ".box_con",
                "title": "div.content_read h1",
                "toc": "#list dd a",
                "tocJump": 9,
                "txt": "#content",
                "filter": [".ywtop", ".header", ".nav", ".bottem1", ".lm", "#page_set", ".bookname~.box_con"],
                "txtfilter": []
            },
            {
                "desc": "biqugetv",
                "main": ".box_con",
                "title": "div.content_read h1",
                "toc": "#list dd a",
                "tocJump": 0,
                "txt": "#content",
                "filter": [".ywtop", ".header", ".nav", ".bottem1", ".lm", "#page_set"],
                "txtfilter": []
            }
        ],
        "states": {
            "fontSize": 16,
            "lineHeight": 16 * lineHeight,
            "toc": false
        },
        "style": "\n            body {\n                background-color: #EAEAEF !important;\n            }\n\n            .bqg.inject.win {\n                width: 55vw !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.5em 1em !important;\n                margin: 0.5em auto !important;\n                width: auto !important;\n            }\n\n            .bqg.inject.title {\n                color: black;\n                background-color: #EAEAEF;\n                font-family: '\u6977\u4F53' !important;\n                cursor: pointer !important;\n            }\n\n            .bqg.inject.title:hover {\n                color: #0258d8 !important;\n            }\n            \n            .hq.inject.toc {\n                font-family: \u5FAE\u8F6F\u96C5\u9ED1,\u6587\u6CC9\u9A7F\u5FAE\u7C73\u9ED1;\n                width: 275px;\n                position: fixed;\n                top: 30px;\n                padding: 5px;\n                display: flex;\n                flex-flow: column;\n                transition: left 0.5s cubic-bezier(0.35, 1.06, 0.83, 0.99);\n                background: rgb(246 246 246 / 60%);\n                border-radius: 8px;\n            }\n\n            .hq.inject ul {\n                max-height: 280px;\n                width: 100%;\n                /*offsetTop \u8BA1\u7B97\u9700\u8981*/\n                position:relative;\n                overflow: auto;\n            }\n\n            .hq.inject ul li {\n                cursor: pointer;\n                margin: 2px;\n                width: 95%;\n                padding: 1px 4px;\n                font-size: 12px;\n                border-radius: 4px;\n            }\n\n            .hq.inject ul li:hover {\n                background: #0258d8;\n                color: #f6f6f6;\n            }\n\n            .hq.inject.toc>h3 {\n                font-size: 1.1rem;\n                font-weight: bold;\n                border-radius: 2px;\n                align-self: center;\n                cursor: pointer;\n                margin: 4px 0 8px 0;\n            }\n\n            .hq.inject.toc>h3:hover {\n                color: #ffa631 !important;\n            }\n            "
    };
    // 查询已经保存的字体信息
    var savedStates = localStorage.getItem("bqg_cfg");
    // 检查是否存在已有设置且和当前版本相符
    var states;
    if (savedStates === null) {
        states = configs.states;
        console.warn("当前状态已保存");
    }
    else {
        var cfg_1 = JSON.parse(savedStates);
        var defaultStates = Object.keys(configs.states);
        var cfg_ = Object.keys(cfg_1);
        var useSaved = true;
        // 检查键是否匹配
        if (defaultStates.length == cfg_.length) {
            for (var _i = 0, _a = Object.keys(cfg_1); _i < _a.length; _i++) {
                var key = _a[_i];
                if (!defaultStates.includes(key)) {
                    useSaved = false;
                    break;
                }
            }
        }
        else {
            useSaved = false;
        }
        if (useSaved) {
            states = cfg_1;
        }
        else {
            states = configs.states;
            console.warn("检测到版本变化,状态已重置");
        }
    }
    // 检测当前的网址,应用对应的设置
    var tmp = configs.sites.filter(function (site) { return document.URL.includes(site.desc); });
    if (tmp.length == 0) {
        console.warn("没有匹配的设置,脚本已终止!");
        return;
    }
    var cfg = tmp[0];
    // 完成样式注入
    GM_addStyle(configs.style);
    var saveStates = function () {
        localStorage.setItem("bqg_cfg", JSON.stringify(states));
    };
    // 下一章
    var prevChapter = function () {
        var _a;
        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;
            }
        }
    };
    // 上一章
    var nextChapter = function () {
        var _a;
        var nexts = document.querySelectorAll("a");
        for (var _i = 0, nexts_1 = nexts; _i < nexts_1.length; _i++) {
            var next = nexts_1[_i];
            if ((_a = next.textContent) === null || _a === void 0 ? void 0 : _a.includes("下一")) {
                next.click();
                break;
            }
        }
    };
    // 目录开关
    var toggleToc = function () {
        var toc = document.querySelector(".hq.inject.toc");
        if (parseInt(toc.style.left) < 0) {
            toc.style.left = "8px";
            states.toc = true;
        }
        else {
            toc.style.left = "-300px";
            states.toc = false;
        }
        // 每一次触发目录操作都保存一次状态
        saveStates();
    };
    // 对可变部分产生影响
    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:" + states.fontSize + "px;line-height:" + states.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 mainWin = document.querySelector(cfg.main);
        mainWin.classList.add("bqg", "inject", "win");
        var title = document.querySelector(cfg.title);
        title.title = "点击显示目录";
        title.classList.add("bqg", "inject", "title");
        title.onclick = function (ev) {
            toggleToc();
            // 避免跳到上一章
            // 比下面的更为具体,所以有效。
            ev.stopPropagation();
        };
        // 阻止双击事件被捕获(双击会回到顶部)
        document.body.ondblclick = function (ev) { return ev.stopImmediatePropagation(); };
        document.body.onclick = function (ev) {
            var root = document.documentElement;
            var winHeight = window.innerHeight;
            // 下半屏单击下滚,反之上滚
            if (ev.clientY > root.clientHeight / 2) {
                if (root.scrollTop + winHeight >= root.scrollHeight) {
                    nextChapter();
                }
                window.scrollBy({ top: (window.innerHeight - lineHeight) * 1 });
            }
            else {
                if (root.scrollTop === 0) {
                    prevChapter();
                }
                window.scrollBy({ top: (window.innerHeight - lineHeight) * -1 });
            }
        };
        document.body.onkeydown = function (ev) {
            switch (ev.key) {
                case "-":
                    states.fontSize -= 2;
                    textWin.style.fontSize = states.fontSize + "px";
                    states.lineHeight = states.fontSize * lineHeight;
                    textWin.style.lineHeight = states.lineHeight + "px";
                    saveStates();
                    break;
                case "=":
                    states.fontSize += 2;
                    textWin.style.fontSize = states.fontSize + "px";
                    states.lineHeight = states.fontSize * lineHeight;
                    textWin.style.lineHeight = states.lineHeight + "px";
                    saveStates();
                    break;
                case "j":
                    window.scrollBy({ top: window.innerHeight - states.lineHeight });
                    break;
                case "k":
                    window.scrollBy({ top: -1 * (window.innerHeight - states.lineHeight) });
                    break;
                case "h":
                    prevChapter();
                    break;
                case "l":
                    nextChapter();
                    break;
                case "t":
                    toggleToc();
                    break;
                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 = (states.toc) ? "8px" : "-300px";
    document.body.append(toc);
    // 目录状态指示灯
    var pointer = document.createElement("h3");
    var pointerColors = { "loaded": "#afdd22", "loading": "#ffa631", "unload": "#ed5736" };
    pointer.title = "点击以重新加载目录";
    pointer.innerHTML = "目<span style='display: inline-block;width: 1em'></span>录";
    pointer.style.color = pointerColors.unload;
    toc.append(pointer);
    // 目录列表
    var ul = document.createElement("ul");
    toc.append(ul);
    // fetchTOC 获取目录信息并重新渲染
    var fetchTOC = function (currentBookLink, pointer) {
        // 修改指示灯状态
        pointer.style.color = pointerColors.loading;
        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.color = pointerColors.loaded;
            },
            onerror: function (_) { return pointer.style.color = pointerColors.unload; }
        });
    };
    var renderToc = function (toc, ul) {
        // 清空旧内容
        ul.innerHTML = "";
        var current = null;
        // 进度计数器
        var counter = 1;
        var _loop_1 = function (lnk) {
            var li = document.createElement("li");
            li.textContent = lnk.title;
            if (current == null && document.URL == lnk.href) {
                li.innerHTML = lnk.title + "<span style=\"flex: 1;\"></span>" + (counter / toc.length * 100).toFixed(1) + "%";
                current = li;
            }
            li.onclick = function (ev) {
                document.location.href = lnk.href;
                ev.stopPropagation();
            };
            ul.append(li);
            counter++;
        };
        for (var _i = 0, toc_1 = toc; _i < toc_1.length; _i++) {
            var lnk = toc_1[_i];
            _loop_1(lnk);
        }
        // 滚动到当前位置,并高亮
        current === null || current === void 0 ? void 0 : current.setAttribute("style", "display:flex;font-weight:bold;background: #0258d8;color: #f6f6f6;");
        ul.scrollTo({ top: (current === null || current === void 0 ? void 0 : current.offsetTop) - 130 });
    };
    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.color = pointerColors.loaded;
        renderToc(JSON.parse(currentBookToc), ul);
    }
    // 单击指示灯刷新目录缓存
    pointer.onclick = function () { return fetchTOC(currentBook, pointer); };
})();