// ==UserScript== // @name 通用阅读器 // @version 0.4.5 // @description 为所有站点增加进入阅读模式按钮,点击后如果匹配成功则自动转码成为通用的阅读器样式方便使用,并提供扩展语音阅读功能(需要浏览器支持,推荐最新版Firefox浏览器) // @author pppploi8 // @match https://*/* // @match http://*/* // @grant none // @namespace https://greasyfork.org/users/240492 // @downloadURL https://update.greasyfork.icu/scripts/377230/%E9%80%9A%E7%94%A8%E9%98%85%E8%AF%BB%E5%99%A8.user.js // @updateURL https://update.greasyfork.icu/scripts/377230/%E9%80%9A%E7%94%A8%E9%98%85%E8%AF%BB%E5%99%A8.meta.js // ==/UserScript== (function() { var $ = function(selector){ return document.querySelector(selector); } var blackList = {"www.baidu.com": true, "www.sogou.com": true, "www.so.com": true, "www.bing.com":true, "cn.bing.com": true, "www.google.com": true, "m.sm.cn": true}; // 通用解析模板 function parseContentAndTitle(){ var mainDom = null; function findMainDom(doms){ var docSize = document.body.scrollHeight * document.body.scrollWidth; for(var i=0;i 0.3 && dom.nodeName !== "CODE" && dom.nodeName !== "PRE"){ // pre和code是代码常用元素块,忽略不认为是正文内容 // 如果innerText字数大于500,则视为正文区 var text = dom.innerText; if (text.length >= 500){ mainDom = dom; } } findMainDom(dom.children||[]); } } findMainDom(document.body.children); if (mainDom){ // 在mainDom同层查找标题 // var titleList = []; // findTitleDom(mainDom.parentNode.children, titleList); // 查找标题逻辑bug较多,暂时改为查找网页title作为标题,后续重写逻辑进行优化 return {content: mainDom.innerText, title: document.title}; } // function findTitleDom(doms, titleList){ // for(var i=0;i= 5 && title.length <= 200){ // titleList.push(dom); // } // } // } // } // } } function parsePageUp(){ var as = document.querySelectorAll('a'); var reg = /上一章|上一篇|上一页|navigation-prev/; for(var i=0;i进入阅读模式'); // 配置阅读模式按钮自动淡出效果 var i = 1; var interval = setInterval(function(){ i -= 0.03; var btn = $('#_er-entryReadMode'); if (!btn) { clearInterval(interval); return; } $('#_er-entryReadMode').style.opacity = i; if (i <= 0) { btn.remove(); clearInterval(interval); } }, 100); $('#_er-entryReadMode').onclick = checkAndCreateReader; $('#_er-NotShowReadMode').onclick = function(){ localStorage['_er-disabled'] = 'true'; $('#_er-entryReadMode').remove(); $('#_er-NotShowReadMode').remove(); } } function checkAndCreateReader(notAlert){ // 通过调用通用模板尝试是否能够成功匹配到阅读内容 var content = parseContentAndTitle(); if (content && content.content){ content.pageup = parsePageUp(); content.pagedown = parsePageDown(); content.pageindex = parsePageIndex(); createReader(content); }else{ if (notAlert !== true){ alert('当前页面解析失败,无法进入阅读模式!'); } } } function setTheme(theme) { switch(theme) { case 'black': $('._er').style.backgroundColor = 'black'; $('._er-title').style.color = 'lightgrey'; $('._er-content').style.color = 'lightgrey'; break; case 'OliveDrab': $('._er').style.backgroundColor = '#D3E1D0'; $('._er-title').style.color = 'black'; $('._er-content').style.color = 'black'; break; case 'Khaki': $('._er').style.backgroundColor = '#F6F2E7'; $('._er-title').style.color = 'black'; $('._er-content').style.color = 'black'; break; case 'blue': $('._er').style.backgroundColor = '#D3E5F9'; $('._er-title').style.color = 'black'; $('._er-content').style.color = 'black'; break; case 'white': $('._er').style.backgroundColor = 'white'; $('._er-title').style.color = 'black'; $('._er-content').style.color = 'black'; break; } localStorage['_er-theme'] = theme; $('._er').dataset['theme'] = theme; } // 创建阅读器 function createReader(content){ $('#_er-entryReadMode') && $('#_er-entryReadMode').remove(); $('#_er-NotShowReadMode') && $('#_er-NotShowReadMode').remove(); addClassAndDom(); if (window.SpeechSynthesisUtterance){ $('#_er-tts').style.display = 'block'; } if (localStorage['_er-theme']) { setTheme(localStorage['_er-theme']); } $('._er-title').innerText = content.title; var contentArr = content.content.split('\n'); var contentHtml = ''; for(var i=0;i'; } contentHtml += '
'; } $('._er-content').innerHTML = contentHtml; var spanNodes = document.querySelectorAll('._er-content span'); for(var i=0;i= width*0.9){ // 后翻一页 $('._er').scrollTop = $('._er').scrollTop + (document.documentElement.clientHeight - 24); } } $('#_er-pageindex').onclick = function(){ if (content.pageindex){ location.href = content.pageindex; }else{ alert('很抱歉,没有匹配到目录!'); } }; $('#_er-switch-theme').onclick = function(){ var current = $('._er').dataset['theme'] || 'white'; var themeList = ['white', 'Khaki', 'blue', 'OliveDrab', 'black']; var index = themeList.indexOf(current); if (index === -1) index = 0; index++; if (index >= themeList.length) { index = 0; } setTheme(themeList[index]); } $('#_er-pageup').onclick = function(){ if (content.pageup){ localStorage['_er-enable'] = 'true'; location.href = content.pageup; }else{ alert('很抱歉,没有匹配到上一页!'); } }; $('#_er-pagedown').onclick = function(){ if (content.pagedown){ localStorage['_er-enable'] = 'true'; location.href = content.pagedown; }else{ alert('很抱歉,没有匹配到下一页!'); } }; $('#_er-pagedown').dataset['nexturl'] = content.pagedown; setFontSize(); setPadding(); // 按钮事件处理 $('#_er-close').onclick = removeDom; $('#_er-font-plus').onclick = function(){ fontsize += 2; setFontSize(); }; $('#_er-font-minus').onclick = function(){ fontsize -= 2; setFontSize(); }; $('#_er-border').onclick= function() { padding = padding == 10 ? 5 : 10; setPadding(); } $('#_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 = ''; if (current){ playText = current.innerText; }else{ playText = $('._er-title').innerText; } if (playText){ var utterThis = new SpeechSynthesisUtterance(); utterThis.text = playText; utterThis.onerror = function(){ $('#_er-tts').dataset['pause'] = 'true'; alert("TTS语音转换文字出现异常,听书已停止运行!"); }; utterThis.onend = function(){ toNextReadPos(); if (!$('._er-current')){ var nextUrl = $('#_er-pagedown').dataset['nexturl']; console.log(nextUrl); if (nextUrl){ localStorage['_er-autoplay'] = 'true'; localStorage['_er-enable'] = 'true'; location.href = nextUrl; } return; } if ($('#_er-tts').dataset['pause'] === 'false'){ playNextText(); } }; speechSynthesis.speak(utterThis); }else{ toNextReadPos(); playNextText(); } } function toNextReadPos(){ var current = $('._er-current'); var nextSpan = null; if (current){ nextSpan = current.nextElementSibling; while(nextSpan && nextSpan.nodeName !== 'SPAN'){ nextSpan = nextSpan.nextElementSibling; } }else{ nextSpan = $('._er-content span'); } if (current) current.classList.remove('_er-current'); if (nextSpan) nextSpan.classList.add('_er-current'); } function toPrevReadPos(){ var current = $('._er-current'); var prevSpan = null; if (current){ prevSpan = current.previousElementSibling; while(prevSpan && prevSpan.nodeName !== 'SPAN'){ prevSpan = prevSpan.previousElementSibling; } } if (current) current.classList.remove('_er-current'); if (prevSpan) prevSpan.classList.add('_er-current'); } function updateReadPos(){ if ($('._er-current')) $('._er').scrollTop = $('._er-current').offsetTop - (document.documentElement.clientHeight / 2); } function setFontSize(){ localStorage["_er_fontsize"] = fontsize; $('._er-title').style.fontSize = (20+fontsize) + 'px'; $('._er-title').style.lineHeight = ((20+fontsize)*1.5) + 'px'; $('._er-content').style.fontSize = (14+fontsize) + 'px'; $('._er-content').style.lineHeight = ((14+fontsize)*1.5) + 'px'; } function setPadding() { localStorage["_er_padding"] = padding; $('._er-content').style.padding = '10px ' + padding + '%'; } var oldOverflow = ''; var oldOnKeyDown = $('body').onkeydown; function removeDom(){ $('._er').remove(); $('body').style.overflow = oldOverflow; $('body').onkeydown = oldOnKeyDown; } function addClassAndDom(){ oldOverflow = $('body').style.overflow; $('body').style.overflow = 'hidden'; $('body').children[0].insertAdjacentHTML('beforeBegin', '
' + '
' + ' ' + '
' + '
' + ' ' + ' ' + ' ' + ' ' + ' ' + ' ' + '
' + '
' + '
' + '
' + '
' + ' ' + ' ' + '
' + '
'); $('body').children[0].insertAdjacentHTML('beforeBegin', ''); } })();