Greasy Fork

Greasy Fork is available in English.

起点小说优化|VIP章节免费阅读|支持本章说显示|自动翻页|简洁风格

提供多功能的起点小说网站优化插件,支持多书源、本章说、翻译、净化等功能

当前为 2024-02-19 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         起点小说优化|VIP章节免费阅读|支持本章说显示|自动翻页|简洁风格
// @version      1.4.5.2
// @description  提供多功能的起点小说网站优化插件,支持多书源、本章说、翻译、净化等功能
// @author       JiGuang
// @namespace    www.xyde.net.cn
// @homepageURL  https://51coolplay.cc
// @match        https://www.qidian.com/*
// @match        https://51coolplay.cc/service/*
// @require https://cdn.jsdelivr.net/npm/sweetalert2@11
// @require https://cdn.staticfile.org/jquery/2.0.3/jquery.min.js
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_openInTab
// @grant GM_xmlhttpRequest
// @grant GM_registerMenuCommand
// @license MIT
// ==/UserScript==

(function() {
    const default_config = `[{"id":1,"open":true,"name":"读书阁书源","author":"Hunter David","offical":false,"version":"1.0.3","description":"文章正文换成读书阁的书源,修复已购买仍然加载的问题","code":"async function onLoad() {function setStatusText(txt){try{document.querySelector('#reader-content > div.min-h-100vh.relative.z-1.bg-inherit > div > div.relative > div > div.text-s-gray-500.mt-4px.text-bo4.flex.items-center.flex-wrap').innerHTML = txt;}catch(err){console.warn('设置失败');}}if(isBuy()){setStatusText('起点小说优化|您已购买本章');return;}setStatusText('起点小说优化|正在加载内容中...');const DOMAIN = 'http://www.dushuge.com/';const book_res_doc = await parseDocFromAjax('get','http://www.dushuge.com/hsdgiohsdigohsog.php?ie=gbk&q=' + readBookName());let books = [];book_res_doc.querySelectorAll('div.bookinfo > h4 > a').forEach((item, index) => {if(item !== undefined){books.push({name:item.innerText,url:item.href,val:calculateTextSimilarity(readBookName(),item.innerText)});}});books.sort((a, b) => b.val - a.val);if(books.length === 0){notify('未找到该书','error');return;}let book = books[0];let chapters = [];const chapter_res_doc = await parseDocFromAjax('get',book.url.replace('https://www.qidian.com/', DOMAIN));chapter_res_doc.querySelectorAll('dl > dd > a').forEach((item, index)=>{if(item !== undefined){chapters.push({name:item.innerText,url:item.href,val:calculateTextSimilarity(readChapterName(),item.innerText)});}});chapters.sort((a, b) => b.val - a.val);if(books.length === 0){notify('未找到该书有效的目录','error');return;}let chapter = chapters[0];const content_res_doc = await parseDocFromAjax('get',chapter.url.replace('https://www.qidian.com/', DOMAIN));const targetContent = content_res_doc.querySelector('#content').innerText;writeContent(targetContent);notify('读书阁书源读取成功');setStatusText('起点小说优化|正在使用读书阁书源阅读');}"},{"id":9999,"open":true,"name":"开启本章说","author":"Hunter David","offical":true,"version":"1.0.0","description":"把阅读页面上的文本重新调整匹配到本章说,已测试读书阁书源可用,其他自测","code":"setTimeout(function() {if(isBuy()){loadComment();}}, 3500);"}]`
    // 取脚本版本
    function getVersion(){
        return '1.4.5.2'
    }
    // 首次更新到新版本的提示
    function firstTip(){
        if(GM_getValue('qdv_'+getVersion(),'') == ''){
            Swal.fire({
                title: "👏欢迎使用起点小说优化",
                text: "1.4.5更新了本章说显示支持,默认开启,可前往插件设置中更换书源和开关本章说、净化等功能(旧版本升级用户需要去设置里开启)",
                icon: "success"
            })
            GM_setValue('qdv_'+getVersion(),'read_notice')
        }
    }
    // 脚本专用:读取配置到51
    function read51Config(){
        // 如果空,就默认装一下插件
        //console.log('config',GM_getValue('config',default_config))
        document.querySelector("#config").value = GM_getValue('config',default_config)
    }
    // 脚本专用:从51写配置
    function save51Config(){
        GM_setValue('config',document.querySelector("#config").value)
    }
    // 脚本专用:运行开启的配置
    function readConfigOpen(is_read_page = true){

        function add_float_menu(){
            let div = document.createElement('div')
            div.innerHTML = '<div style="position:fixed;top:10px;right:10px;"><button id="b56">点我进入插件设置</button></div>'
            document.body.appendChild(div);
            document.querySelector("#b56").onclick = ()=>{
                GM_openInTab('https://51coolplay.cc/service/book/settings.php')
            }
        }

        window.onLoad = ()=>{
            notify('您在当前页面没有开启任何插件!!','error')
            add_float_menu()
        }

        let codes = ''
        try{
            const config_str = GM_getValue('config',default_config)
            // console.log(config_str)
            const config_items = JSON.parse(config_str)
            // console.log(config_items)
            //筛选插件代码
            if(is_read_page){
                codes = config_items.filter(e => e.open).map(e => e.code).join(';')
            }else{
                //全局起点页面插件需要配置global=true,然后插件里自己设计路径检测
                codes = config_items.filter(e => e.open).filter(e => e.global).map(e => e.code).join(';')
            }
        }catch(err){
            console.warn('加载配置失败0',err)
            notify('加载配置失败,请去设置页面重新配置','error')
            add_float_menu()
            return
        }
        //注入插件
        console.log(codes)
        try{
            eval(codes)
            //执行启动函数(书源专用)注意,设置中的自定义插件会默认添加onload函数包裹
            onLoad()
        }catch(err){
            console.warn('加载配置失败',err)
            notify('加载配置失败,请去设置页面检查是否启用了不兼容的插件','error')
            add_float_menu()
            return
        }
    }
    // 内置函数:读取页面书名
    function readBookName(){
        const bookNameElement = document.querySelector("#r-breadcrumbs > a.text-s-gray-900");
        if (bookNameElement) {
            // 使用正则表达式去掉括号内的内容
            const rawName = bookNameElement.innerText;
            const cleanedName = rawName.replace(/\([^)]*\)/g, '').trim();
            console.log(`BookName:${cleanedName}`)
            return cleanedName;
        } else {
            return '未知'
            // 或者返回一个默认的名称,或者抛出错误,具体根据需求来定
        }
    }
    // 内置函数:读取章节名
    function readChapterName(){
        let ele = document.querySelector("#reader-content > div.min-h-100vh.relative.z-1.bg-inherit > div > div.relative > div > h1")
        if (ele) {
            let res = '' + ele.innerText
            res = res.replace(' ', '')
            console.log(`BookChapter:${res}`)
            return res
        }
        return '未知'
    }
    // 内置函数:读取正文
    function readContent(){
        return document.querySelector("#reader-content > div.min-h-100vh.relative.z-1.bg-inherit > div > div.relative > div > main").innerText
    }
    // 内置函数:将请求的url的html内容转化成document对象
    async function parseDocFromAjax(method,url){
      console.log('请求url:',url)
      return new Promise((resolve,reject) => {
          GM_xmlhttpRequest({
              method,
              url,
              onload:(res) => {
                //console.log('response',res)
                  let htmldoc = document.createElement('html')
                  let htmlstr = res.responseText
                  // 修复 某图片自动加载的问题
                  htmlstr = htmlstr.replace(/http /g, "https")
                  htmlstr = htmlstr.replace(/img src/g, "a url")
                  htmlstr = htmlstr.replace(/onerror/g, "class")
                  htmldoc.innerHTML = htmlstr
                  resolve(htmldoc)
              },
              onerror:(err) => {
                  reject(err)
              }
          })
      })
    }
    // 内置函数:axios/fetch风格的跨域请求
    async function request(url,data = '',method = 'GET'){
        console.log('请求url1:',url)
        return new Promise((resolve,reject) => {
          GM_xmlhttpRequest({
              method,
              url,
              data,
              onload:(res) => {
                //console.log('response1',res.response)
                resolve(JSON.parse(res.response))
              },
              onerror:(err) => {
                  reject(err)
              }
          })
      })
    }
    async function loadComment(){
        //先加载本章说
        let cid = location.href.split('/')[location.href.split('/').length-2]
        let bid = location.href.split('/')[location.href.split('/').length-3]
        const res = await request(`https://www.qidian.com/ajax/chapterReview/reviewSummary?_csrfToken=${document.cookie.split(';').find(e=>e.indexOf("_csrfToken")!=-1).split('=')[1]}&bookId=${bid}&&chapterId=${cid}`, true)
        let content = document.querySelector("#reader-content > div.min-h-100vh.relative.z-1.bg-inherit > div > div.relative > div > main").innerHTML
        let txts = content.split('<br><br>')
        let contents = ''
        txts.forEach((txt,index) =>{
            let num = res.data.list.find(e=>e.segmentId == index + 1).reviewNum
            let hot_style = res.data.list.find(e=>e.segmentId == index + 1).isHotSegment?'data-type="hot"':''
            let plus = `<p><span id="content-${index + 1}" class="content-text" data-count="${num}" data-index="${index + 1}">${txt}</span><span class="review" ${hot_style} data-index="${index + 1}"><span class="review-icon"></span><span class="review-count">${num}</span><!----></span></p>`
            let comment_ui = `<div id="side-sheet-${index + 1}"hidden style="display:none;box-shadow: 0 8px 16px rgba(0, 0, 0, 0.5);z-index:9999;max-height: 600px"class="bg-b-gray-50 noise-bg border-l border-outline-black-8 h-full w-400px absolute right-0"><button onclick="document.querySelector('#side-sheet-${index + 1}').style.display = 'none'"data-v-63a3e543=""class="bg-s-gray-100 w-28px h-28px rounded-1 flex items-center justify-center hover-24 active-10 p-0 absolute right-10px top-10px"><span class="icon-close text-20px text-s-gray-400"></span></button><div data-v-8a7b341d=""data-v-6c740737=""class="h-full flex flex-col"><div data-v-8a7b341d=""class="flex items-end pt-42px pb-10px px-32px <sm:px-16px <sm:py-15px <sm:border-b <sm:border-outline-black-8"><h2 data-v-8a7b341d=""class="font-medium text-rh4 text-s-gray-900 <sm:text-rh6">评论</h2><span data-v-8a7b341d=""class="text-s3 text-s-gray-500 ml-8px font-medium <sm:text-s4">${num}条</span></div><div data-v-8a7b341d=""class="flex-1 overflow-auto overscroll-contain"><div data-v-8a7b341d=""class="min-h-[calc(100%+20px)]"><!----><ul data-v-8a7b341d="">加载中...</ul><div data-v-8a7b341d=""class="h-80px"></div></div></div></div></div>`
            contents += plus
            contents += comment_ui

        })
        document.querySelector("#reader-content > div.min-h-100vh.relative.z-1.bg-inherit > div > div.relative > div > main").innerHTML = contents
        txts.forEach((item,index) =>{
            document.querySelector("#content-"+(index + 1)).addEventListener("click", async function() {
                // 显示本章说吧!(等到点击的时候再加载书评,省流)
                console.log('click'+(index + 1))
                let template_contents = ''
                //请求起点的书评API,自己动手,丰衣足食~
                let res = await request(`https://www.qidian.com/ajax/chapterReview/reviewList?bookId=${bid}&chapterId=${cid}&page=1&pageSize=20&segmentId=${index+1}&type=2&_csrfToken=${document.cookie.split(';').find(e=>e.indexOf("_csrfToken")!=-1).split('=')[1]}`)
                res.data.list.forEach((item,index)=>{
                    let template_unit = `<li data-v-8a7b341d=""class="px-32px py-16px <sm:px-16px"><div><div class="group"><div class="flex items-center py-1px"><a target="_blank"href="//my.qidian.com/user/${item.userId}/"class="flex items-center min-w-0"><img class="w-28px h-28px mr-10px rounded-1 border border-outline-black-8"alt="cartilage"src="${item.avatar}"><div class="self-start pt-1px flex items-center"><span class="font-medium text-s-gray-500 text-s3 truncate mr-4px">${item.nickName}</span><!----></div></a><a target="_blank"href="https://jubao.yuewen.com/report/report?type=0&amp;id=208188071492190208&amp;appId=10&amp;areaId=1&amp;site=10&amp;extra=9069458404256003&amp;subType=7&amp;desc=1"class="group-hover:flex hidden ml-auto text-s-gray-500 text-s4 items-center font-medium flex-shrink-0"><span class="icon-warning text-16px mr-2px"></span>举报</a></div><div class="pl-38px"><p class="text-s-gray-900 text-16px leading-24px"><span class="inline-flex w-30px h-18px items-center justify-center overflow-hidden mr-4px align-text-bottom"><span class="whitespace-nowrap text-primary-red-500 text-20px font-medium h-32px flex items-center px-8px rounded-8px border border-primary-red-300 transform scale-50">精华</span></span><!----><span class="leading-24px whitespace-pre-wrap">${item.content}</span></p><!----><!----><div class="flex items-center mt-4px text-c12 text-s-gray-400"><span class="truncate"><span>${item.level}楼·</span>${item.createTime}${item.ipAddress}</span><button class="flex-shrink-0 ml-4px mr-auto text-secondary-blue-500 font-medium h-28px">回复</button><button class="hidden flex-shrink-0 ml-8px items-center text-c12 text-s-gray-500 group-hover:flex h-28px"><span class="icon-thumb-up text-20px mr-2px down"></span>踩</button><button class="flex items-center flex-shrink-0 text-c12 h-28px ml-12px text-s-gray-500"><span class="icon-thumb-up text-20px mr-2px"></span>${item.likeCount}</button></div></div></div></div></li>`
                    template_contents += template_unit
                })
                document.querySelector("#side-sheet-"+(index + 1)).innerHTML = document.querySelector("#side-sheet-"+(index + 1)).innerHTML.replace('加载中...',template_contents)
                document.querySelector("#side-sheet-"+(index + 1)).style.display = 'block'
            });
        })

    }
    // 内置函数:写入正文
    async function writeContent(content = '',html = false){
        if(!html){
            document.querySelector("#reader-content > div.min-h-100vh.relative.z-1.bg-inherit > div > div.relative > div > main").innerText = content
        }else{
            document.querySelector("#reader-content > div.min-h-100vh.relative.z-1.bg-inherit > div > div.relative > div > main").innerHTML = content
        }
        // loadComment() 不要默认开启,预留给插件去开启,可能会有部分书源不支持,需要测试;我是拿读书阁测的OK
    }
    // 内置函数:是否已订阅
    function isBuy(){
        return readContent().length > 200
    }
    // 内置函数:计算文本相似度,返回0-1之间的数值,0.5以上可以采信
    function calculateTextSimilarity(text1, text2) {
    // 将文本转换成小写并去除空格
    text1 = text1.toLowerCase().replace(/\s/g, "");
    text2 = text2.toLowerCase().replace(/\s/g, "");
    // 计算两个文本的交集
    const intersection = text1.split("").filter(char => text2.includes(char));
    // 计算相似度
    const similarity = intersection.length / (text1.length + text2.length - intersection.length);
    return similarity;
}
    //内置函数:提示用户
    function notify(title = '操作成功', type = 'success', show = true) {
        console.log(title)
        const Toast = Swal.mixin({
            toast: true,
            position: 'top-end',
            showConfirmButton: false,
            timer: 2000,
            timerProgressBar: true,
            didOpen: (toast) => {
                toast.addEventListener('mouseenter', Swal.stopTimer)
                toast.addEventListener('mouseleave', Swal.resumeTimer)
            }
        })
        if (show)
            Toast.fire({
                icon: type,
                title: title
            })
        return Toast
    }
    // 配置网站就读取配置到网站上,1秒保存一次
    if(location.href.indexOf('51coolplay.cc')!= -1){
        read51Config()
        setInterval(()=>{ save51Config() },1000)
    }
    // 应用网站就把配置运行好
    if(location.href.indexOf('qidian.com/chapter')!= -1){
        firstTip()
        readConfigOpen()
    }
    // 起点其他页面预留的坑位,计划更新:全书txt解析下载、游客云书架、移动端起点适配...
    else if(location.href.indexOf('qidian.com')!= -1){
        readConfigOpen(false)
    }
    GM_registerMenuCommand('⚙️打开设置', ()=>{GM_openInTab('https://51coolplay.cc/service/book/settings.php?v='+getVersion(), {active: !0})})
    GM_registerMenuCommand('♻️重置设置', ()=>{GM_deleteValue('config');notify('重置成功')})
})();