🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

微信读书自动阅读

微信读书阅读自动滚动, 触底自动翻页

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name		微信读书自动阅读
// @name:en		WeChatReadAutoScroll
// @description		微信读书阅读自动滚动, 触底自动翻页
// @description:en	微信读书阅读自动滚动, 触底自动翻页
// @version		1.0.0
// @match		https://weread.qq.com/web/reader/*
// @author		Yiero
// @icon		https://weread.qq.com/favicon.ico
// @namespace		https://github.com/AliubYiero/TamperMonkeyScripts/
// @license		GPL
// @grant		GM_registerMenuCommand
// @grant		GM_unregisterMenuCommand
// @grant		GM_setValue
// @grant		GM_getValue
// @grant		GM_deleteValue
// @grant		GM_listValues
// @run-at		document-idle
// ==/UserScript==
var __defProp = Object.defineProperty;

var __defNormalProp = (obj, key, value2) => key in obj ? __defProp(obj, key, {
    enumerable: true,
    configurable: true,
    writable: true,
    value: value2
}) : obj[key] = value2;

var __publicField = (obj, key, value2) => {
    __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value2);
    return value2;
};

class Info {
    constructor(projectName) {
        __publicField(this, "projectName");
        __publicField(this, "header");
        this.projectName = projectName;
        this.header = `[${projectName}]`;
    }
    log(...msg) {
        (() => {})(...this.contentInfo(...msg));
    }
    info(...msg) {
        console.info(...this.contentInfo(...msg));
    }
    warn(...msg) {
        console.warn(...this.contentInfo(...msg));
    }
    error(...msg) {
        console.error(...this.contentInfo(...msg));
    }
    contentInfo(...msg) {
        return [ this.header, `[${(new Date).toLocaleString("zh-ch")}]`, ...msg ];
    }
}

function MathCeilFloat(number, decimal = 0) {
    decimal = Math.pow(10, decimal);
    return Math.ceil(number * decimal) / decimal;
}

function isReachedPageBottom() {
    const {scrollTop: scrollTop, clientHeight: clientHeight, scrollHeight: scrollHeight} = document.documentElement;
    return scrollTop + clientHeight >= scrollHeight;
}

class ScrollOptionsImpl {
    constructor() {
        __publicField(this, "_delayPerMs", 0);
        __publicField(this, "_frameDuration", 0);
        __publicField(this, "_framePerSecond", 0);
        __publicField(this, "_movementDistancePerSecond", 0);
    }
    get delayPerMs() {
        return this._delayPerMs;
    }
    set delayPerMs(value) {
        if (typeof value === "string") {
            const scrollPageDuration = window.innerHeight / this.movementDistancePerSecond * 1e3;
            print.log(scrollPageDuration, this.movementDistancePerSecond);
            try {
                this._delayPerMs = eval(value.replace("auto", String(scrollPageDuration)));
            } catch (e) {
                this._delayPerMs = scrollPageDuration;
            }
        } else {
            this._delayPerMs = value;
        }
    }
    get movementDistancePerFrame() {
        return MathCeilFloat(this.movementDistancePerSecond / this.framePerSecond, 3);
    }
    get frameDuration() {
        return MathCeilFloat(1e3 / this._frameDuration);
    }
    get framePerSecond() {
        return this._framePerSecond;
    }
    set framePerSecond(value2) {
        this._framePerSecond = value2;
    }
    get movementDistancePerSecond() {
        return this._movementDistancePerSecond;
    }
    set movementDistancePerSecond(value2) {
        this._movementDistancePerSecond = value2;
    }
}

class GlobalAutoScroll {
    constructor(movementDistancePerSecond, delayPerMs = "auto", framePerSecond = 60) {
        __publicField(this, "options", new ScrollOptionsImpl);
        __publicField(this, "timer");
        this.options.movementDistancePerSecond = movementDistancePerSecond;
        this.options.delayPerMs = delayPerMs;
        this.options.framePerSecond = framePerSecond;
    }
    open() {
        if (this.timer) {
            this.close();
        }
        scrollStatusStorage.set("scrolling");
        print.info("等待滚动: ", this.options.delayPerMs);
        this.timer = window.setTimeout((() => {
            this.timer = window.setInterval((() => {
                this.scroll();
                if (isReachedPageBottom()) {
                    this.close();
                }
            }), this.options.frameDuration);
        }), this.options.delayPerMs);
    }
    close() {
        scrollStatusStorage.set("scroll-end");
        clearTimeout(this.timer);
        clearInterval(this.timer);
        this.timer = void 0;
    }
    scroll() {
        const movementDistancePerFrame = this.options.movementDistancePerFrame;
        scrollBy(0, movementDistancePerFrame);
    }
}

class GMConfigMenu {
    constructor(callback) {
        __publicField(this, "menuId", 0);
        __publicField(this, "callback");
        this.callback = callback;
    }
    open(title) {
        if (this.menuId) {
            this.close();
        }
        this.menuId = GM_registerMenuCommand(title, this.callback);
    }
    close() {
        GM_unregisterMenuCommand(this.menuId);
        this.menuId = 0;
    }
}

class LocalStorage {
    constructor(key) {
        __publicField(this, "key");
        this.key = key;
    }
    get(defaultValue) {
        return localStorage.getItem(this.key) || defaultValue || "";
    }
    remove() {
        const oldValue = this.get();
        const newValue = void 0;
        dispatchEvent(new CustomEvent("storageUpdate", {
            detail: {
                key: this.key,
                newValue: newValue,
                oldValue: oldValue
            }
        }));
        localStorage.removeItem(this.key);
    }
    set(value2) {
        const oldValue = this.get();
        const newValue = value2;
        dispatchEvent(new CustomEvent("storageUpdate", {
            detail: {
                key: this.key,
                newValue: newValue,
                oldValue: oldValue
            }
        }));
        localStorage.setItem(this.key, value2);
    }
}

class SessionStorage {
    constructor(key) {
        __publicField(this, "key");
        this.key = key;
    }
    get(defaultValue) {
        return sessionStorage.getItem(this.key) || defaultValue || "";
    }
    remove() {
        const oldValue = this.get();
        const newValue = void 0;
        dispatchEvent(new CustomEvent("storageUpdate", {
            detail: {
                key: this.key,
                newValue: newValue,
                oldValue: oldValue
            }
        }));
        sessionStorage.removeItem(this.key);
    }
    set(value2) {
        const oldValue = this.get();
        const newValue = value2;
        dispatchEvent(new CustomEvent("storageUpdate", {
            detail: {
                key: this.key,
                newValue: newValue,
                oldValue: oldValue
            }
        }));
        sessionStorage.setItem(this.key, value2);
    }
}

new MouseEvent("mouseenter", {
    button: 0,
    bubbles: true,
    cancelable: true,
    clientX: 819,
    clientY: 413
});

new MouseEvent("mousedown", {
    bubbles: true,
    cancelable: true,
    button: 0
});

new MouseEvent("mouseup", {
    bubbles: true,
    cancelable: true,
    button: 0
});

new MouseEvent("click", {
    bubbles: true,
    cancelable: true,
    button: 0
});

function fireKeyEvent(el = document, evtType, keyCode) {
    let evtObj;
    if (document.createEvent) {
        if (window.KeyEvent) {
            evtObj = document.createEvent("KeyEvents");
            evtObj.initKeyEvent(evtType, true, true);
            el.dispatchEvent(evtObj);
            return;
        }
        evtObj = document.createEvent("UIEvents");
        evtObj.initUIEvent(evtType, true, true);
        delete evtObj.keyCode;
        if (typeof evtObj.keyCode === "undefined") {
            Object.defineProperty(evtObj, "keyCode", {
                value: keyCode
            });
        } else {
            evtObj.key = String.fromCharCode(keyCode);
        }
        if (typeof evtObj.ctrlKey === "undefined") {
            Object.defineProperty(evtObj, "ctrlKey", {
                value: true
            });
        } else {
            evtObj.ctrlKey = true;
        }
        el.dispatchEvent(evtObj);
        return;
    }
}

const print = new Info("WeChatReadAutoScroll");

const scrollStatusStorage = new SessionStorage("scrollStatus");

(async () => {
    const scrollSpeedController = new GMConfigMenu((() => {
        const result = prompt("页面滚动速度(px/s)");
        if (!result) {
            return;
        }
        localStorage.setItem("scrollSpeed", result);
    }));
    scrollSpeedController.open("[配置] 滚动速度");
    const scrollDelayController = new GMConfigMenu((() => {
        const result = prompt("滚动开启延时 ( auto | (auto / 2) | number ) (ms)");
        if (!result) {
            return;
        }
        localStorage.setItem("scrollDelay", result);
    }));
    scrollDelayController.open("[配置] 滚动开启延时");
    function scrollSwitch() {
        let globalAutoScroll;
        const scrollOpenController = new GMConfigMenu(scrollOpenMenuCallback);
        function scrollOpenMenuCallback() {
            const scrollSpeedStorage = new LocalStorage("scrollSpeed");
            const scrollDelayStorage = new LocalStorage("scrollDelay");
            globalAutoScroll = new GlobalAutoScroll(+scrollSpeedStorage.get("100"), scrollDelayStorage.get("auto"), 60);
            globalAutoScroll.open();
            window.addEventListener("click", (() => {
                globalAutoScroll.close();
            }), {
                once: true
            });
            scrollOpenController.close();
            scrollCloseController.open("关闭滚动");
        }
        const scrollCloseController = new GMConfigMenu((() => {
            globalAutoScroll.close();
            scrollCloseMenuCallback();
        }));
        function scrollCloseMenuCallback() {
            scrollCloseController.close();
            scrollOpenController.open("开启滚动");
        }
        scrollOpenController.open("开启滚动");
        scrollStatusStorage.set("scroll-start");
        window.addEventListener("storageUpdate", (e => {
            const event = e;
            if (event.detail.key === "scrollStatus" && event.detail.newValue === "scroll-end") {
                scrollCloseMenuCallback();
                if (isReachedPageBottom()) {
                    fireKeyEvent(document, "keydown", 39);
                    scrollOpenMenuCallback();
                }
            }
        }));
    }
    scrollSwitch();
})();