简单小说阅读器

为各个小说站增加小说阅读器,遇到支持的小说站后会自动转码成为通用的阅读器样式方便使用,并为小说站扩展语音阅读功能(需要浏览器支持,推荐最新版Firefox浏览器)

目前為 2019-02-01 提交的版本,檢視 最新版本

// ==UserScript==
// @name         简单小说阅读器
// @version      0.1.3
// @description  为各个小说站增加小说阅读器,遇到支持的小说站后会自动转码成为通用的阅读器样式方便使用,并为小说站扩展语音阅读功能(需要浏览器支持,推荐最新版Firefox浏览器)
// @author       pppploi8
// @match        http*://*/*
// @grant        none
// @namespace https://gf.qytechs.cn/users/240492
// ==/UserScript==

(function() {
    var $ = function(selector){
        return document.querySelector(selector);
    }

    var rules = {'www.shencou.com': {path: '/read/.*\.html', func: function(){
        if (location.pathname.endsWith('/index.html')) return null; // 目录页,不解析
        var title = $('h1').innerText;
        $('h1').style.display = 'none';
        var content = $('#content').innerText;
        $('h1').style.display = 'block'; // 恢复原网页
        return {
            title: title,
            content: content,
            pageup: $('img[src="http://www.shencou.com/logo/h.gif"]').parentNode.href,
            pageindex: location.href.substring(0, location.href.lastIndexOf('/') + 1),
            pagedown: $('img[src="http://www.shencou.com/logo/x.gif"]').parentNode.href
        };
    }},'m.shencou.com':{path:'/wapreader.php', func: function(){
        return {
            title: $('#nr_title').innerText,
            content: $('#nr').innerText,
            pageup: $('#pb_prev').href,
            pageindex: $('#pb_mulu').href,
            pagedown: $('#pb_next').href
        };
    }},'www.booktxt.net': {path: '.*\.html', func: function(){
        return {
            title: $('h1').innerText,
            content: $('#content').innerText,
            pageup: jQuery('.bottem1 a').eq(1).attr('href'),
            pageindex: location.href.substring(0, location.href.lastIndexOf('/') + 1),
            pagedown: jQuery('.bottem1 a').eq(3).attr('href')
        };
    }},'m.wuyanxia.net': {path: '.*\.html', func: function(){
        return {
            title: jQuery('.zhong').text(),
            content: jQuery('#nr')[0].innerText,
            pageup: jQuery('.nr_page a').eq(3).attr('href'),
            pageindex: location.href.substring(0, location.href.lastIndexOf('/')) + '.html',
            pagedown: jQuery('.nr_page a').eq(5).attr('href')
        };
    }},'m.9dxs.com':{path: '.*\.html', func: function(){
        return commonTemplate1(Zepto);
    }},'m.booktxt.net': {path: '/wapbook/.*\.html', func: function(){
        var ret = commonTemplate1(Zepto);
        ret.content = ret.content.replace('本章未完,请点击下一页继续阅读....', '');
        return ret;
    }},'m.biqukan.com': {path: '.*\.html', func: function(){
        var ret = commonTemplate2(jQuery);
        ret.content = ret.content.substring(content.indexOf('\n') + 1, content.lastIndexOf('\n'));
        return ret;
    }},'m.biqiuge.com': {path: '.*\.html', func: function(){
        var ret = commonTemplate2(Zepto);
        var content = ret.content;
        content = content.substring(content.indexOf('\n') + 1);
        content = content.replace('记住手机版网址:m.biqiuge.com', '').replace('『加入书签,方便阅读』', '');
        ret.content = content;
        return ret;
    }}};// 解析规则列表

    // 通用模板1,适用于所有使用Zepto/jQuery,标题是.title,内容是#chaptercontent,翻页是pt_的页面
    function commonTemplate1($){
        $('#chaptercontent p').hide();
        var content = $('#chaptercontent')[0].innerText;
        $('#chaptercontent p').show();

        return {
            title: $('.title').text(),
            content: content,
            pageup: $('#pt_prev').attr('href'),
            pageindex: $('#pt_mulu').attr('href'),
            pagedown: $('#pt_next').attr('href')
        };
    }

    // 通用模板2,适用于所有使用Zepto/jQuery,标题是.title,内容是#chaptercontent,翻页是pb_的页面
    function commonTemplate2($){
        var content = $('#chaptercontent')[0].innerText;
        return {
            title: $('.title').text(),
            content: content,
            pageup: $('#pb_prev').attr('href'),
            pageindex: $('#pb_mulu').attr('href'),
            pagedown: $('#pb_next').attr('href')
        };
    }

    var host = location.hostname;
    var path = location.pathname;
    var rule = rules[host];

    var fontsize = parseInt(localStorage["_er_fontsize"]||0);
    var autoplay = false;
    if (localStorage['_er-autoplay'] === 'true'){
        autoplay = true;
    }
    delete localStorage['_er-autoplay'];

    if (rule && new RegExp(rule.path).test(path)){
        var htmlContent = rule.func();
        if (htmlContent){
            createReader(htmlContent);
        }
    }


    // 创建阅读器
    function createReader(content){
        addClassAndDom();
        if (window.SpeechSynthesisUtterance){
            $('#_er-tts').style.display = 'block';
        }
        $('._er-title').innerText = content.title;
        var contentArr = content.content.split('\n');
        var contentHtml = '';
        for(var i=0;i<contentArr.length;i++){
            var line = contentArr[i];
            if (line){
                contentHtml += '<span>' + line + '</span>';
            }
            contentHtml += '<br>';
        }
        $('._er-content').innerHTML = contentHtml;
        var spanNodes = document.querySelectorAll('._er-content span');
        for(var i=0;i<spanNodes.length;i++){
            spanNodes[i].onclick = function(){
                for(var j=0;j<spanNodes.length;j++){
                    spanNodes[j].classList.remove('_er-current');
                }
                this.classList.add('_er-current');
            }
        }
        $('._er-content').onclick = function(e){ // 适用于墨水屏的左右点击无动画翻页
            var x = e.pageX;
            var width = document.documentElement.clientWidth;
            if (x <= width*0.1){ // 前翻一页
                $('._er').scrollTop = $('._er').scrollTop - (document.documentElement.clientHeight - 24)
            }else if(x >= width*0.9){ // 后翻一页
                $('._er').scrollTop = $('._er').scrollTop + (document.documentElement.clientHeight - 24);
            }
        }
        $('#_er-pageindex').onclick = function(){
            location.href = content.pageindex;
        };
        $('#_er-pageup').onclick = function(){
            location.href = content.pageup;
        };
        $('#_er-pagedown').onclick = function(){
            location.href = content.pagedown;
        };
        $('#_er-pagedown').dataset['nexturl'] = content.pagedown;
        setFontSize();

        // 按钮事件处理
        $('#_er-close').onclick = removeDom;
        $('#_er-font-plus').onclick = function(){
            fontsize += 2;
            setFontSize();
        };
        $('#_er-font-minus').onclick = function(){
            fontsize -= 2;
            setFontSize();
        };

        $('#_er-tts').onclick = function(){
            if (this.dataset['pause'] === 'true'){
                // 开始播放
                this.innerText = '停止';
                this.dataset['pause'] = 'false';
                playNextText();
            }else{
                this.innerText = '听书';
                this.dataset['pause'] = 'true';
            }
        };

        if (autoplay){
            $('#_er-tts').innerText = '停止';
            $('#_er-tts').dataset['pause'] = 'false';
            playNextText();
        }else{
            $('#_er-tts').dataset['pause'] = 'true';
        }
    }

    // 听书功能
    function playNextText(){
        updateReadPos();
        var current = $('._er-current');
        var playText = '';
        var nextSpan = null;
        if (current){
            playText = current.innerText;
            nextSpan = current.nextElementSibling;
            while(nextSpan && nextSpan.nodeName !== 'SPAN'){
                nextSpan = nextSpan.nextElementSibling;
            }
        }else{
            playText = $('._er-title').innerText;
            nextSpan = $('._er-content span');
        }
        if (playText){
            var utterThis = new SpeechSynthesisUtterance();
            utterThis.text = playText;
            utterThis.onerror = function(){
                $('#_er-tts').dataset['pause'] = 'true';
                alert("TTS语音转换文字出现异常,听书已停止运行!");
            };
            utterThis.onend = function(){
                if (!nextSpan){
                    localStorage['_er-autoplay'] = 'true';
                    location.href = $('#_er-pagedown').dataset['nexturl'];
                    return;
                }
                if ($('#_er-tts').dataset['pause'] === 'false'){
                    if ($('._er-current')) $('._er-current').classList.remove('_er-current');
                    nextSpan.classList.add('_er-current');
                    playNextText();
                }
            };
            speechSynthesis.speak(utterThis);
        }else{
            if ($('._er-current')) $('._er-current').classList.remove('_er-current');
            nextSpan.classList.add('_er-current');
            playNextText();
        }
    }

    function updateReadPos(){
        if ($('._er-current'))
            $('._er').scrollTop =  $('._er-current').offsetTop;
    }

    function setFontSize(){
        localStorage["_er_fontsize"] = fontsize;
        $('._er-title').style.fontSize = (20+fontsize) + 'px';
        $('._er-content').style.fontSize = (14+fontsize) + 'px';
    }

    var oldOverflow = '';

    function removeDom(){
        $('._er').remove();
        $('body').style.overflow = oldOverflow;
    }

    function addClassAndDom(){
        oldOverflow = $('body').style.overflow;
        $('body').style.overflow = 'hidden';

        $('body').innerHTML +=
            '<style>' +
            '._er{' +
            '    position: fixed;' +
            '    left: 0;' +
            '    right: 0;' +
            '    top: 0;' +
            '    bottom: 0;' +
            '    overflow: auto;' +
            '    background-color: white;' +
            '    z-index: 201901272211;' +
            '}' +
            '._er-title{' +
            '    text-align: center;' +
            '    font-size: 20px;' +
            '    font-weight: 900;' +
            '    padding: 10px 10%;' +
            '    color: black;' +
            '}' +
            '._er-content{' +
            '    padding: 10px 10%;' +
            '    font-size: 14px;' +
            '    color: black;' +
            '}' +
            '._er-tools{' +
            '    margin-top: 10px;' +
            '    margin-bottom: 10px;' +
            '    text-align: center;' +
            '}' +
            '._er-tools button{' +
            '    cursor: pointer;' +
            '    color: green;' +
            '    border: 1px solid black;' +
            '    padding: 5px;' +
            '    border-radius: 10px;' +
            '}' +
            '._er-tts button{' +
            '    width: 50px;' +
            '    height: 50px;' +
            '    position: fixed;' +
            '    right: 15px;' +
            '    bottom: 15px;' +
            '    z-index: 201901272212;' +
            '    color: green;' +
            '    border: 1px solid black;' +
            '    opacity: 0.5;' +
            '    cursor: pointer;' +
            '    border-radius: 25px;' +
            '    display: none;' +
            '}' +
            '._er-current{' +
            '    background-color: yellow;' +
            '}' +
            '</style>';
        $('body').innerHTML +=
            '<div class="_er">' +
            '    <div class="_er-tts">' +
            '        <button type="button" id="_er-tts">听书</button>' +
            '    </div>' +
            '    <div class="_er-tools">' +
            '        <button type="button" id="_er-pageindex">目录</button>' +
            '        <button type="button" id="_er-font-plus">字体+</button>' +
            '        <button type="button" id="_er-font-minus">字体-</button>' +
            '        <button type="button" id="_er-close">返回原网页</button>' +
            '    </div>' +
            '    <div class="_er-title"></div>' +
            '    <div class="_er-content">' +
            '    </div>' +
            '    <div class="_er-tools">' +
            '        <button type="button" id="_er-pageup">上一页</button>' +
            '        <button type="button" id="_er-pagedown">下一页</button>' +
            '    </div>' +
            '</div>';
        $('head').innerHTML += '<meta name="viewport" content="width=device-width, initial-scale=1" />';
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址