仿生阅读(Bionic Reading)

通过Alt+B(Mac为Control+B)开关的通用仿生阅读脚本,只作用于英文内容,优先处理字典中的词,并根据单词长度进行加粗

// ==UserScript==
// @name         仿生阅读(Bionic Reading)
// @namespace    http://tampermonkey.net/
// @version      1.7
// @description  通过Alt+B(Mac为Control+B)开关的通用仿生阅读脚本,只作用于英文内容,优先处理字典中的词,并根据单词长度进行加粗
// @author       yitong233
// @match        *://*/*
// @license      MIT
// @icon         https://cdn.icon-icons.com/icons2/869/PNG/64/read_mode_icon-icons.com_68002.png
// @homepageURL  https://greasyfork.org/zh-CN/scripts/509335-%E4%BB%BF%E7%94%9F%E9%98%85%E8%AF%BB-bionic-reading
// @supportURL   https://greasyfork.org/zh-CN/scripts/509335-%E4%BB%BF%E7%94%9F%E9%98%85%E8%AF%BB-bionic-reading/feedback
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    let isEnabled = false; // 初始状态为关闭

    // 常见后缀字典
    const suffixes = [
        'ly', 'ion', 'ness', 'ed', 'al', 'ive', 'ing', 'ar', 'er', 'ir', 'or', 'ur',
        'itude', 'able', 'ible', 'ary', 'ate', 'ess', 'less', 'ship', 'fy', 'ic', 'um',
        'us', 'ty', 'ity', 'ant', 'ent', 'end', 'and', 'ance', 'ence', 'ancy', 'ency',
        'id', 'te', 'ize', 'ise', 'ous', 'hood', 'icle', 'cle', 'et', 'kin', 'let', 'y',
        'ward', 'wise', 'dom', 'craft', 'cracy', 'ice', 'ology', 'graphy', 'ry', 'ment',
        'ship', 'fy', 'en', 'ate', 'ish'
    ];

    // 介词和常用词字典
    const prepositions = [
        'the', 'and', 'in', 'on', 'at', 'by', 'with', 'about', 'against', 'between', 'into',
        'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up', 'down',
        'over', 'under', 'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where',
        'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other', 'some'
    ];

    // 判断是否为介词或常用词
    function isPreposition(word) {
        return prepositions.includes(word.toLowerCase());
    }

    // 格式化单词:根据单词长度加粗不同数量的字母,并根据介词或句首单词进行特殊处理
    function formatWord(word, isFirstWord) {
        if (!word) {
            return ''; // 处理空字符串的情况
        }
        else{
            // 如果是介词或者句子的第一个单词,只加粗第一个字母
        if (isPreposition(word) || isFirstWord) {
            return `<b>${word[0]}</b>${word.slice(1)}`;
        }

        let boldLength;
        const wordLength = word.length;

        // 根据单词长度决定加粗字母的数量
        if (wordLength <= 2) {
            boldLength = 1; // 1-2长度的单词加粗第一个字母
        } else if (wordLength <= 5) {
            boldLength = 2; // 3-5长度的单词加粗前两个字母
        } else {
            boldLength = Math.min(4, wordLength); // 6个及以上的单词加粗前三到四个字母
        }

        let boldPart = word.slice(0, boldLength);
        let restPart = word.slice(boldLength);
        return `<b>${boldPart}</b>${restPart}`;
        }
    }

    // 处理单个文本节点
    function processTextNode(textNode) {
        const sentences = textNode.textContent.split(/(?<=\.)\s+/); // 以句子分割
        let formattedText = sentences.map(sentence => {
            const words = sentence.split(/\s+/);
            return words.map((word, index) => formatWord(word, index === 0)).join(' '); // 句首单词特殊处理
        }).join(' ');

        // 用于将HTML插入到文本节点
        const span = document.createElement('span');
        span.innerHTML = formattedText;

        // 替换当前的文本节点
        textNode.replaceWith(span);
    }

    // 遍历元素的子节点,处理其中的文本节点
    function traverseAndFormatText(node) {
        node.childNodes.forEach(child => {
            if (child.nodeType === Node.TEXT_NODE && child.textContent.trim().length > 0) {
                // 处理文本节点
                processTextNode(child);
            } else if (child.nodeType === Node.ELEMENT_NODE && child.tagName !== 'SCRIPT' && child.tagName !== 'STYLE' && child.tagName !== 'PRE') {
                // 递归处理子节点
                traverseAndFormatText(child);
            }
        });
    }

    // 应用到整个网页的英文内容
    function applyBionicReading() {
        const bodyContents = document.body; // 获取整个页面的内容
        traverseAndFormatText(bodyContents); // 处理文本节点
    }

    // 启用或禁用仿生阅读功能
    function toggleBionicReading() {
        isEnabled = !isEnabled; // 切换状态
        if (isEnabled) {
            applyBionicReading();
            console.log("Bionic Reading 已启用");
        } else {
            location.reload(); // 重新加载页面恢复原始状态
            console.log("Bionic Reading 已禁用");
        }
    }
     // 判断操作系统
        var isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
    // 监听键盘事件,根据操作系统选择不同的快捷键
    document.addEventListener('keydown', function (e) {
        if ((isMac && e.ctrlKey && e.key === 'b') || (!isMac && e.altKey && e.key === 'b')) {
            toggleBionicReading();
        }
    });
})();