您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
微信读书的阅读字体修改为苍耳今楷,加减宽度,上下划显示隐藏导航栏,多档滚动速度,自动翻页,仅适配weread.qq.com站点
当前为
// ==UserScript== // @name 微信读书Weread阅读综合功能版 // @version 0.3.5 // @author !Sylas // @contributor SimonDW;Li_MIxdown;hubzy;xvusrmqj;LossJ;JackieZheng;das2m;harmonyLife // @namespace http://tampermonkey.net/ // @description 微信读书的阅读字体修改为苍耳今楷,加减宽度,上下划显示隐藏导航栏,多档滚动速度,自动翻页,仅适配weread.qq.com站点 // @match https://weread.qq.com/web/reader/* // @icon https://weread.qq.com/favicon.ico // @grant GM_addStyle // @grant unsafeWindow // @license MIT // ==/UserScript== // .readerControls { // width: 120px; display: flex !important; flex-wrap: wrap; !important; flex-direction: row; !important; margin-left: calc(50% - 130px) !important; // } GM_addStyle(` * { font-family: SourceHanSerifCN-Bold !important; } .readerControls { margin-left: calc(50% - 130px) !important; } .readerControls_item, .readerControls_fontSize { margin-right: 10px !important; color:#6a6c6c !important; cursor:pointer !important; } .readerChapterContent { margin-left: 30px !important; margin-right: 30px !important; } `); const ElementUtils = { cssGet: (tar_elm, property) => { /** * 获取 css 属性 * * tar_elm: elementNode * property: string */ return window.getComputedStyle(tar_elm).getPropertyValue(property); }, cssSet: (tar_elm, property, value, priority) => { /** * 设置 css 属性 * * tar_elm: node * property: string * value: string | number | null * priority: string | null */ return tar_elm.style.setProperty(property, value, priority); }, htmlGet: (tar_elm, is_out) => { /** * 获取 HTML 代码 * * tar_elm: node * is_in: bool */ if (is_out) { return tar_elm.outerHTML; } return tar_elm.innerHTML; }, insertHtml: (tar_elm, ins_html, position) => { /** * 在目标元素指定位置插入 HTML 代码 * * tar_elm: node * ins_html: string * position: string -> 可选项:beforeBegin、afterBegin、beforeEnd、afterEnd */ position = typeof position === "undefined" ? "beforeEnd" : position; tar_elm.insertAdjacentHTML(position, ins_html); }, insertElement: (tar_elm, ins_elm, position) => { /** * 在目标元素指定位置插入元素 * * tar_elm: node * ins_elm: node * position: string -> 可选项:beforeBegin、afterBegin、beforeEnd、afterEnd */ position = typeof position === "undefined" ? "beforeEnd" : position; tar_elm.insertAdjacentElement(position, ins_elm); }, }; let div_body = $css("body"); let div_controls = $css(".readerControls"); let div_top_bar = $css(".readerTopBar"); let btn_width_add = $css("#width-add"); let btn_width_dev = $css("#width-dev"); let btn_scroll_on = $css("#scroll-on"); let btn_scroll_off = $css("#scroll-off"); let btn_turn_tips = $css("#turn-page-tips"); let scroll_speed = 0; (async function () { "use strict"; // 最多等待 30 秒页面加载完成 let book = await waitElement(".wr_canvasContainer canvas", 30000); if (!book) { alert("书本内容加载失败,请手动刷新页面!"); return; } div_body = $css("body"); div_controls = $css(".readerControls"); div_top_bar = $css(".readerTopBar"); // 添加功能按键; // div_controls.appendHtml(` // <div class="readerControls"> // <button title="等待翻页" id='turn-page-tips' class='readerControls_item'>等待翻页</button> // <button title="加宽" id='width-add' class='readerControls_item'>加宽</button> // <button title="减宽" id='width-dev' class='readerControls_item'>减宽</button> // <button title="播放X0" id='scroll-on' class='readerControls_item'>播放X0</button> // <button title="停止播放" id='scroll-off' class='readerControls_item'>停止播放</button> // </div>`); div_controls.insertHtml(` <button title="等待翻页" id='turn-page-tips' class='readerControls_item'>等待翻页</button> <button title="加宽" id='width-add' class='readerControls_item'>加宽</button> <button title="减宽" id='width-dev' class='readerControls_item'>减宽</button> <button title="播放X0" id='scroll-on' class='readerControls_item'>播放X0</button> <button title="停止播放" id='scroll-off' class='readerControls_item'>停止播放</button> `); btn_width_add = $css("#width-add"); btn_width_dev = $css("#width-dev"); btn_scroll_on = $css("#scroll-on"); btn_scroll_off = $css("#scroll-off"); btn_turn_tips = $css("#turn-page-tips"); // 额外功能按钮功能实现 btn_width_add.onclick = () => changeWidth(true); btn_width_dev.onclick = () => changeWidth(false); btn_scroll_on.onclick = () => { scroll_speed++; if (scroll_speed == 1) { autoScroll(); } btn_scroll_on.innerHTML = "播放X" + scroll_speed; }; btn_scroll_off.onclick = () => { scroll_speed = 0; btn_scroll_on.innerHTML = "播放X0"; }; // 顶部导航栏优化 let last_scroll_top = getScrollTop(); let opacity = 1; window.onscroll = () => { let curr_scroll_top = getScrollTop(); if (curr_scroll_top < last_scroll_top) { // 上划显示 opacity = opacity + 0.05 >= 1 ? 1 : opacity + 0.05; } else { // 上划隐藏 opacity = opacity - 0.03 <= 0 ? 0 : opacity - 0.03; } div_top_bar.cssSet("opacity", opacity); last_scroll_top = curr_scroll_top; }; })(); function changeWidth(isAdd, step) { step = typeof step === "undefined" ? 60 : step; let div_content = $css(".app_content"); let width = Number(div_content.cssGet("max-width").replace("px", "")); if (isAdd) { width += step; } else { width -= step; } div_content.cssSet("max-width", width + "px"); div_top_bar.cssSet("max-width", width + "px"); let resize_event = new Event("resize"); window.dispatchEvent(resize_event); } // 滑动屏幕,滚至页面底部 async function autoScroll(step, delay) { step = typeof step === "undefined" ? 1 : step; delay = typeof delay === "undefined" ? 2000 : delay; while (scroll_speed > 0) { window.scrollBy(0, step); if (isPageBottom()) { await nextPage(); } await sleep(delay / scroll_speed / scroll_speed); } } async function nextPage(sleep_time) { sleep_time = typeof sleep_time === "undefined" ? 6000 : sleep_time; let btn_turn = document.querySelector(".readerFooter_button"); while (true) { if (isShowInView(btn_turn) && scroll_speed > 0) { console.log(`wait ${sleep_time / 1000} seconds. turn page.`); let last_time = sleep_time / 1000; while (last_time > 0) { btn_turn_tips.innerHTML = `${last_time}s翻页`; last_time--; await sleep(1000); } pressKey("right"); await sleep(3000); btn_turn_tips.innerHTML = `等待翻页`; break; } } } /** ------ 常用函数 ------ **/ function initElement(elements) { /** * 初始化元素属性和函数 * * element: elementNode */ if (!Array.isArray(elements)) { elements = [elements]; } for (let element of elements) { for (let fn_name in ElementUtils) { element[fn_name] = (...args) => { return ElementUtils[fn_name](element, ...args); }; } // element.append = (new_ele) => { // return appendElement(element, new_ele); // }; // element.insert = (new_ele) => { // return insertElement(element, new_ele); // }; // element.insertHtml = (html_content, position) => { // return insertHtml(element, html_content, position); // }; // element.cssSet = (property, value, priority) => { // return cssSet(element, property, value, priority); // }; // element.cssGet = (property) => { // return cssGet(element, property); // }; } } function $css(query) { /** * css 选择器,单元素 * * query: string */ let elm = document.querySelector(query); if (!elm) { return; } initElement(elm); return elm; } function $cssAll(query) { /** * css 选择器,单元素 * * query: string */ let elms = Array.apply(null, document.querySelectorAll(query)); if (elms.length === 0) { return; } initElement(elms); return elms; } function $xpa(query, node) { /** * xpath 选择器,单元素 * * query: string * node: elementNode */ node = typeof node === "undefined" ? document : node; let elm = document.evaluate(query, node).iterateNext(); if (!elm) { return; } initElement(elm); return elm; } function $xpaAll(query, node) { /** * xpath 选择器,多元素 * * query: string * node: elementNode */ node = typeof node === "undefined" ? document : node; let elm_list = []; let elm_box = document.evaluate(query, document); let elm = elm_box.iterateNext(); if (!elm) { return; } while (elm) { elm_list.push(elm); elm = elm_box.iterateNext(); } initElement(elm_list); return elm_list; } function sleep(ms) { ms = typeof ms === "undefined" ? 1000 : ms; /** * 休眠函数,单位:ms * 使用方法: * sleep(500).then(() => { Do something after the sleep! }); * 或者 * await sleep(500); Do something after the sleep! */ return new Promise((resolve) => setTimeout(resolve, ms)); } function isShowInView(element) { /** * 判断元素是否出现在视窗中 */ if (element === null || element === undefined) { return false; } let documentHeight = Math.max( document.documentElement.scrollHeight, document.documentElement.offsetHeight, document.documentElement.clientHeight ); let screenHeight = window.innerHeight || documentHeight; let screenWidth = window.innerWidth || document.documentElement.clientWidth; let { top, right, bottom, left } = element.getBoundingClientRect(); return ( top >= 0 && left >= 0 && right <= screenWidth && bottom <= screenHeight ); } function isExistElement(css_selector) { /** * 判断指定元素是否存在页面中 */ if ($css(css_selector)) { return true; } return false; } async function waitElement(css_selector, max_wait_ms) { /** * 等待指定元素出现 */ max_wait_ms = typeof max_wait_ms === "undefined" ? 3000 : max_wait_ms; let start_time = new Date().getTime(); let elm = $css(css_selector); while (!elm && start_time + max_wait_ms >= new Date().getTime()) { await sleep(300); elm = $css(css_selector); if (elm) { break; } } return elm; } function getScrollTop() { /** * 滚动条在Y轴上已经滚动的距离 */ return document.documentElement.scrollTop || document.body.scrollTop; } function getScrollHeight() { /** * 整个页面的高度 */ return document.documentElement.scrollHeight || document.body.scrollHeight; } function getWindowHeight() { /** * 浏览器可视窗口高度 */ return document.documentElement.clientHeight || document.body.clientHeight; } function isPageBottom(deviation_value) { /** * 判断页面是否滚动到底,默认允许3个像素的误差,大部分情况下总是会差0.3-0.8像素 */ deviation_value = typeof deviation_value === "undefined" ? 3 : deviation_value; if ( getScrollHeight() - getScrollTop() - getWindowHeight() < deviation_value ) { return true; } return false; } function pressKeyByCode(code) { /** * 按键触发,根据传入的按键编号 * * code: Number */ return document.dispatchEvent( new KeyboardEvent("keydown", { bubbles: true, cancelable: true, keyCode: code, }) ); } function pressKey(name) { /** * 按键触发,根据传入的按键名 * * name: string */ const KeyNameToCode = { back: 8, tab: 9, clear: 12, enter: 13, shift: 16, ctrl: 17, alt: 18, capelock: 20, esc: 27, space: 32, pageup: 33, pagedown: 34, end: 35, home: 36, left: 37, up: 38, right: 39, down: 40, insert: 45, delete: 46, 0: 48, 1: 49, 2: 50, 3: 51, 4: 52, 5: 53, 6: 54, 7: 55, 8: 56, 9: 57, a: 65, b: 66, c: 67, d: 68, e: 69, f: 70, g: 71, h: 72, i: 73, j: 74, k: 75, l: 76, m: 77, n: 78, o: 79, p: 80, q: 81, r: 82, s: 83, t: 84, u: 85, v: 86, w: 87, x: 88, y: 89, z: 90, f1: 112, f2: 113, f3: 114, f4: 115, f5: 116, f6: 117, f7: 118, f8: 119, f9: 120, f10: 121, f11: 122, f12: 123, // 数字小键盘部分 n0: 96, n1: 97, n2: 98, n3: 99, n4: 100, n5: 101, n6: 102, n7: 103, n8: 104, n9: 105, "n*": 106, "n+": 107, nenter: 108, "n-": 109, "n.": 110, "n/": 111, numlock: 144, ";": 186, ":": 186, "=": 187, "+": 187, ",": 188, "<": 188, "-": 189, _: 189, ".": 190, ">": 190, "/": 191, "?": 191, "`": 192, "~": 192, "[": 219, "{": 219, "\\": 220, "|": 220, "]": 221, "}": 221, "'": 222, '"': 222, }; return pressKeyByCode(KeyNameToCode[name.toLowerCase()]); }