您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已经安装了用户样式管理器,让我安装!)
// ==UserScript==
// @name Fanqie Novel Free Reading
// @namespace https://github.com/SmashPhoenix272
// @version 5.2.1
// @description 番茄小说免费网页阅读 不用客户端 可下载小说
// @description:zh-cn 番茄小说免费网页阅读 不用客户端 可下载小说
// @description:en Fanqie Novel Reading, No Need for a Client, Novels Available for Download
// @author ibxff, SmashPhoenix272
// @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) {
if (!ele) return;
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) => {
if (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.code === 200 && data.data && data.data.content) {
return data.data.content;
}
throw new Error('Unexpected response format');
}
(function() {
'use strict';
const path = window.location.href.match(/\/([^/]+)\/\d/)?.[1];
switch(path){
case 'reader':
const toolbar = document.querySelector("#app > div > div > div > div.reader-toolbar > div > div.reader-toolbar-item.reader-toolbar-item-download");
const text = toolbar?.querySelector('div:nth-child(2)');
if (toolbar && text) {
mark(toolbar);
text.innerHTML = 'Processing';
}
document.title = document.title.replace(/在线免费阅读_番茄小说官网$/, '')
var currentURL = window.location.href
setInterval(() => window.location.href !== currentURL ? location.reload() : null, 1000);
// Get content div for both PC and mobile layouts
let cdiv;
// Try PC layout first
cdiv = document.getElementsByClassName('muye-reader-content noselect')[0];
if (cdiv) {
console.log('Found PC layout content div');
cdiv.classList = cdiv.classList[0];
} else {
// Try mobile layout
console.log('Trying mobile layout');
const html0 = document.getElementById('html_0');
if (!html0) {
console.log('Could not find html_0 for mobile layout');
return;
}
cdiv = html0.children[2] || html0.children[0];
if (!cdiv) {
console.log('Could not find content div in mobile layout');
return;
}
console.log('Found mobile layout content div');
}
console.log('Content div found:', cdiv);
console.log('Getting chapter ID...');
const url = window.location.href;
const regex = /\/(\d+)/;
const match = url.match(regex);
if (!match) {
console.log('Could not extract chapter ID');
return;
}
const extractedId = match[1];
console.log('Chapter ID:', extractedId);
const apiUrl = `https://api.cenguigui.cn/api/tomato/content.php?item_id=${extractedId}`;
console.log('Making API request...');
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();
document.getElementsByClassName('pay-page')[0]?.remove();
cdiv.innerHTML = content.replace(/\n/g, "</p><p>").replace(/ /g,"").replace(/(.*?)\n/, '');
// Clean up any remaining pay-related elements
document.getElementById('html_0')?.classList.remove('pay-page-html');
if (toolbar && text) {
toolbar.style.backgroundColor = '#B0E57C'
text.innerHTML = 'Successed'
hideElement(toolbar)
}
} catch (error) {
console.error('Error processing content:', error);
if (toolbar && text) {
toolbar.style.backgroundColor = 'pink'
text.innerHTML = 'Failed'
hideElement(toolbar)
}
}
}
},
onerror: function(error) {
if (toolbar && text) {
toolbar.style.backgroundColor = 'pink'
text.innerHTML = 'Failed'
hideElement(toolbar)
}
console.error(`Fetch error: ${error}`);
}
});
break;
case 'page':
const infoName = document.querySelector("#app > div > div.muye.muye-page > div > div.page-wrap > div > div.page-header-info > div.info > div.info-name > h1")?.innerHTML;
const authorName = document.querySelector(".author-name-text")?.innerHTML;
const totalChapters = document.querySelector(".page-directory-header h3")?.textContent.match(/(\d+)章/)?.[1] || '';
const infoLabels = Array.from(document.querySelectorAll('.info-label span')).map(span => span.textContent).join(' ');
const wordCount = document.querySelector('.info-count-word')?.textContent.trim();
const lastUpdate = document.querySelector('.info-last')?.textContent.trim();
const abstract = document.querySelector("#app > div > div.muye.muye-page > div > div.page-body-wrap > div > div.page-abstract-content > p")?.innerHTML;
var content = 'Using Free Fanqie script download\n\n' +
'作者:' + authorName + '\n' +
'书名:' + infoName + '\n' +
'标签:' + infoLabels + '\n' +
'字数:' + wordCount + '\n' +
'更新:' + lastUpdate + '\n\n' +
'简介:' + abstract + '\n'
content = content.replace(/undefined|null|NaN/g,'')
const processContentForDownload = (content) => {
return content
.replace(/<[^>]+>/g, '') // Remove all HTML tags
.replace(/ /g, ' ') // Replace HTML spaces
.replace(/</g, '<') // Replace HTML entities
.replace(/>/g, '>')
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/\n\s*\n/g, '\n') // Remove multiple consecutive newlines
.split('\n') // Split into paragraphs
.map(para => ' ' + para) // Add 2 spaces to each paragraph
.join('\n') // Join back together
.trim();
};
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")
if (!download) return;
const downloadSpan = download.querySelector('button > span')
if (downloadSpan) downloadSpan.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");
if (!parentElement) return;
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(){
if (!books.length) return;
const ele = books[0].querySelector('a')
if (!ele) return;
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);
if (!match) return;
const extractedId = match[1];
const apiURL = `https://api.cenguigui.cn/api/tomato/content.php?item_id=${extractedId}`;
const charset = selectElement.value
content += '\n\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 });
const fileName = totalChapters ? `${infoName}_${totalChapters}章.txt` : `${infoName}.txt`;
saveAs(blob, fileName);
return
}
else{
next()
}
}
catch(e){
ele.style.backgroundColor = 'pink'
ele.style.border = "2px solid pink"
next()
}
}
},
onerror: function(error) {
console.error(`Fetch error: ${error}`);
ele.style.backgroundColor = 'pink'
ele.style.border = "2px solid pink"
next()
},
ontimeout: function(error) {
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;
}
})();