Greasy Fork

Greasy Fork is available in English.

Fanqie Novel Free Reading

番茄小说免费网页阅读 不用客户端 可下载小说

当前为 2024-11-23 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name              Fanqie Novel Free Reading
// @namespace         https://github.com/SmashPhoenix272
// @version           4...2.8.4.3+
// @description       番茄小说免费网页阅读 不用客户端 可下载小说
// @description:zh-cn 番茄小说免费网页阅读 不用客户端 可下载小说
// @description:en    Fanqie Novel Reading, No Need for a Client, Novels Available for Download
// @author            ibxff
// @license           MIT License
// @match             https://fanqienovel.com/*
// @require           https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
// @icon              data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDQ4IDQ4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0zNS40Mjg2IDQuODg0MzVDMzkuNjQ2MyA0Ljg4NDM1IDQzLjA4MTYgOC4zMTk3MyA0My4wODE2IDEyLjUzNzRWMzUuNDI4NkM0My4wODE2IDM5LjY0NjMgMzkuNjQ2MyA0My4wODE2IDM1LjQyODYgNDMuMDgxNkgxMi41Mzc0QzguMzE5NzMgNDMuMDgxNiA0Ljg4NDM1IDM5LjY0NjMgNC44ODQzNSAzNS40Mjg2VjEyLjUzNzRDNC44ODQzNSA4LjMxOTczIDguMzE5NzMgNC44ODQzNSAxMi41Mzc0IDQuODg0MzVIMzUuNDI4NlpNMzUuNDI4NiA0SDEyLjUzNzRDNy44MDk1MiA0IDQgNy44MDk1MiA0IDEyLjUzNzRWMzUuNDI4NkM0IDQwLjE1NjUgNy44MDk1MiA0My45NjYgMTIuNTM3NCA0My45NjZIMzUuNDI4NkM0MC4xNTY1IDQzLjk2NiA0My45NjYgNDAuMTU2NSA0My45NjYgMzUuNDI4NlYxMi41Mzc0QzQ0IDcuODA5NTIgNDAuMTU2NSA0IDM1LjQyODYgNFoiIGZpbGw9IiMzMzMiLz48cGF0aCBkPSJNMjkuMTAxNiA0VjEyLjQwMTRMMzIuMzMyOSAxMC41NjQ2TDM1LjU2NDEgMTIuNDAxNFY0SDI5LjEwMTZaIiBmaWxsPSIjMzMzIi8+PHBhdGggZD0iTTI0LjAzNCAxOC4yODU4QzE1LjgzNjcgMTguMjg1OCA4LjU1NzgyIDIxLjg1NzIgNCAyNy4zNjc0VjM1LjQyODZDNCA0MC4xNTY1IDcuODA5NTIgNDMuOTY2IDEyLjUzNzQgNDMuOTY2SDM1LjQyODZDNDAuMTU2NSA0My45NjYgNDMuOTY2IDQwLjE1NjUgNDMuOTY2IDM1LjQyODZWMjcuMjY1NEMzOS40MDgyIDIxLjc4OTIgMzIuMTk3MyAxOC4yODU4IDI0LjAzNCAxOC4yODU4Wk0xNC42MTIyIDM3LjY3MzVDMTMuMTE1NiAzNy42NzM1IDEyLjQwMTQgMzcuMTI5MyAxMi40MDE0IDM2LjQxNUMxMi40MDE0IDM1LjcwMDcgMTMuMDgxNiAzNS4xMjI1IDE0LjU3ODIgMzUuMTIyNUMxNi4wNzQ4IDM1LjEyMjUgMTcuODc3NiAzNi4zODEgMTcuODc3NiAzNi4zODFDMTcuODc3NiAzNi4zODEgMTYuMTA4OCAzNy42NzM1IDE0LjYxMjIgMzcuNjczNVpNMTUuODM2NyAzMS4yMTA5QzE0Ljc0ODMgMzAuMTU2NSAxNC42NDYzIDI5LjI3MjIgMTUuMTU2NSAyOC43NjJDMTUuNjY2NyAyOC4yNTE4IDE2LjU1MSAyOC4zMTk4IDE3LjYzOTUgMjkuNDA4MkMxOC43Mjc5IDMwLjQ2MjYgMTkuMDY4IDMyLjYwNTUgMTkuMDY4IDMyLjYwNTVDMTkuMDY4IDMyLjYwNTUgMTYuODkxMiAzMi4yNjU0IDE1LjgzNjcgMzEuMjEwOVpNMjQuMDM0IDMwLjQ2MjZDMjQuMDM0IDMwLjQ2MjYgMjIuNzQxNSAyOC43Mjc5IDIyLjcwNzUgMjcuMTk3M0MyMi43MDc1IDI1LjcwMDcgMjMuMjUxNyAyNC45ODY0IDIzLjk2NiAyNC45ODY0QzI0LjY4MDMgMjQuOTg2NCAyNS4yNTg1IDI1LjY2NjcgMjUuMjU4NSAyNy4xNjMzQzI1LjI5MjUgMjguNjkzOSAyNC4wMzQgMzAuNDYyNiAyNC4wMzQgMzAuNDYyNlpNMzAuMzYwNSAyOS4zNzQyQzMxLjQ0OSAyOC4zMTk4IDMyLjMzMzMgMjguMjUxOCAzMi44NDM1IDI4LjcyNzlDMzMuMzUzNyAyOS4yMzgxIDMzLjI1MTcgMzAuMTIyNSAzMi4xNjMzIDMxLjE3NjlDMzEuMDc0OCAzMi4yMzEzIDI4LjkzMiAzMi41Mzc1IDI4LjkzMiAzMi41Mzc1QzI4LjkzMiAzMi41Mzc1IDI5LjI3MjEgMzAuNDI4NiAzMC4zNjA1IDI5LjM3NDJaTTMzLjM1MzcgMzcuNjczNUMzMS44NTcxIDM3LjY3MzUgMzAuMDg4NCAzNi4zNDcgMzAuMDg4NCAzNi4zNDdDMzAuMDg4NCAzNi4zNDcgMzEuODU3MSAzNS4wODg1IDMzLjM4NzggMzUuMDg4NUMzNC44ODQ0IDM1LjA4ODUgMzUuNTk4NiAzNS43MDA3IDM1LjU2NDYgMzYuMzgxQzM1LjU2NDYgMzcuMTI5MyAzNC44NTAzIDM3LjY3MzUgMzMuMzUzNyAzNy42NzM1WiIgZmlsbD0iIzMzMyIvPjwvc3ZnPg==
// @grant             GM_xmlhttpRequest
// @updateURL
// ==/UserScript==

const styleElement = document.createElement("style");
const cssRule = `
    @keyframes hideAnimation {
      0% {
        opacity: 1;
      }
      50% {
        opacity: 0.75;
      }
      100% {
        opacity: 0;
        display: none;
      }
    }

    option:checked {
        background-color: #ffb144;
        color: white;
    }
    `;

styleElement.innerHTML = cssRule;
document.head.appendChild(styleElement);

function hideElement(ele) {
  ele.style.animation = "hideAnimation 1.5s ease";
  ele.addEventListener("animationend", function () {
    ele.style.display = "none";
  });
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const mark=(ele)=>ele.style.boxShadow = "0px 0px 50px rgba(0, 0, 0, 0.2)";

// Function to extract content from different response formats
function extractContent(data) {
    if (data.data && data.data.data && data.data.data.content) {
        return data.data.data.content;
    } else if (data.data && data.data.content) {
        return data.data.content;
    } else if (data.code === 0 && data.data && data.data.content) {
        // Handle HTML encoded content
        const decodedContent = data.data.content
            .replace(/\u003cp\u003e/g, '<p>')
            .replace(/\u003c\/p\u003e/g, '</p>');
        return decodedContent;
    }
    throw new Error('Unexpected response format');
}

(function() {
    'use strict';
    switch(window.location.href.match(/\/([^/]+)\/\d/)[1]){
        case 'reader':
            const div=document.querySelector("#app > div > div > div > div.reader-toolbar > div > div.reader-toolbar-item.reader-toolbar-item-download")
            const text=div.querySelector('div:nth-child(2)')
            mark(div)
            div.querySelector('div:nth-child(2)').innerHTML='Processing'

            document.title=document.title.replace(/在线免费阅读_番茄小说官网$/, '')

            var currentURL=window.location.href
            setInterval(() => window.location.href !== currentURL ? location.reload() : null, 1000);

            const cdiv=document.getElementsByClassName('muye-reader-content noselect')[0]
            cdiv.classList=cdiv.classList[0]
            const url = window.location.href;
            const regex = /\/(\d+)/;
            const match = url.match(regex);
            const extractedId = match[1];
            const apiUrl = `https://novel.snssdk.com/api/novel/reader/full/v1/?item_id=${extractedId}`;

            GM_xmlhttpRequest({
                method: "GET",
                url: apiUrl,
                onload: function(response) {
                    if (response.status === 200) {
                        try {
                            const data = JSON.parse(response.responseText);
                            const content = extractContent(data);
                            console.log(content);
                            document.getElementsByClassName('muye-to-fanqie')[0]?.remove();
                            cdiv.innerHTML = content.replace(/\n/g, "</p>").replace(/  /g,"<p>");

                            div.style.backgroundColor='#B0E57C'
                            text.innerHTML='Successed'
                            hideElement(div)
                        } catch (error) {
                            console.error('Error processing content:', error);
                            div.style.backgroundColor='pink'
                            text.innerHTML='Failed'
                            hideElement(div)
                        }
                    }
                },
                onerror: function(error) {
                    div.style.backgroundColor='pink'
                    text.innerHTML='Failed'
                    hideElement(div)
                    console.error(`Fetch error: ${error}`);
                }
            });
     break;

     case 'page':
            const title = document.querySelector("#app > div > div.muye.muye-page > div > div.page-wrap > div > div.page-header-info > div.info > div.info-name > h1").innerHTML
            var content='Using Free Fanqie script download\n'+
                        +document.querySelector("#app > div > div.muye.muye-page > div > div.page-wrap > div > div.page-header-info > div.info > div.info-name > h1").innerHTML+'\n'
                        +document.getElementsByClassName('page-header-info')[0].textContent
                        .replace('继续阅读').replace('Download Fanqie Novel').replace('开始阅读').replace('*Download Novel')
                       +'\n'+document.querySelector("#app > div > div.muye.muye-page > div > div.page-body-wrap > div > div.page-abstract-content > p").innerHTML
            content=content.replace(/undefined|null|NaN/g,'')
            console.log(content)

            const processContentForDownload = (content) => {
                return content
                    .replace(/<(?!\/?p\b)[^>]+>/g, '')  // Remove all HTML tags except <p>
                    .replace(/<p>/g, '\n')  // Replace opening <p> with newline
                    .replace(/<\/p>/g, '')  // Remove closing </p>
                    .replace(/\n\s*\n/g, '\n')  // Remove multiple consecutive newlines
                    .trim();  // Remove leading/trailing whitespace
            };

            sleep(1500).then(()=>{
            document.querySelector("#app > div > div.muye.muye-page > div > div.page-wrap > div > div.page-header-info > div.info > div.download-icon.muyeicon-tomato").remove()
            const download=document.querySelector("#app > div > div.muye.muye-page > div > div.page-wrap > div > div.page-header-info > div.info > a")
            download.querySelector('button > span').innerHTML='*Download Novel'
            download.href='javascript:void 0'

            const parentElement = document.querySelector("#app > div > div.muye.muye-page > div > div.page-wrap > div > div.page-header-info > div.info");
            const selectElement = document.createElement("select");
            selectElement.className = "byte-btn byte-btn-primary byte-btn-size-large byte-btn-shape-square muye-button";
            const options = [
                {text: "UTF-8" },
                {text: "GBK" },
                {text: "UNICODE" },
                {text:'UTF-16'},
                {text:'ASCII'}
            ];
            options.forEach(function(optionData) {
                var option = document.createElement("option");
                option.text = optionData.text;
                option.value= optionData.text
                selectElement.appendChild(option);
            });
            selectElement.style.position = "absolute";
            selectElement.style.left = "320px";
            selectElement.style.bottom = "0px";
            selectElement.style.height = "32px";
            selectElement.style.width = "80px";
            selectElement.style.fontSize = "15px";
            parentElement.appendChild(selectElement);

            const books=Array.from(document.getElementsByClassName('chapter-item'))
            var accomplish=false

            function next(){
                const ele=books[0].querySelector('a')
                ele.style.border = "3px solid navajowhite"
                ele.style.borderRadius = "5px"
                ele.style.backgroundColor = "navajowhite"
                const url = ele.href;
                console.log(url)
                const regex = /\/(\d+)/;
                const match = url.match(regex);
                const extractedId = match[1];
                const apiURL = `https://novel.snssdk.com/api/novel/reader/full/v1/?item_id=${extractedId}`;
                const charset=selectElement.value

                content+='\n\n'+ele.innerHTML+'\n'
                GM_xmlhttpRequest({
                    method: "GET",
                    url: apiURL,
                    'Content-Type': "application/json; charset="+charset,
                    onload: function(response) {
                        if (response.status === 200) {
                            try{
                                const data = JSON.parse(response.responseText);
                                const chapterContent = extractContent(data);
                                const processedContent = processContentForDownload(chapterContent);
                                content += processedContent;
                                ele.style.backgroundColor='#D2F9D1'
                                ele.style.border = "2px solid #D2F9D1"
                                books.shift()
                                console.log(books)
                                if(!books.length){
                                    console.log('Download succesfully, saving')
                                    console.log(charset)
                                    const blob = new Blob([new TextEncoder(charset).encode(content)], { type: `text/plain;charset=`+charset });
                                    saveAs(blob, title+".txt");
                                    return
                                }
                                else{
                                    next()
                                }
                            }
                            catch(e){
                                ele.style.backgroundColor='pink'
                                ele.style.border = "2px solid pink"
                                next()
                            }
                        }
                    },
                    onerror: function(error) {
                        hideElement(div)
                        console.error(`Fetch error: ${error}`);
                        ele.style.backgroundColor='pink'
                        ele.style.border = "2px solid pink"
                        next()
                    },
                    ontimeout : function(error) {
                        hideElement(div)
                        console.error(`Fetch error: ${error}`);
                        ele.style.backgroundColor='pink'
                        ele.style.border = "2px solid pink"
                        next()
                    }
                });
             }
             download.addEventListener('click',next)
             download.addEventListener('click',()=>{download.style.display='none';selectElement.style.display='none'})
            })
      break;
    }
})();