// ==UserScript==
// @name 起点小说vip自动换源
// @namespace http://tampermonkey.net/
// @version 2.4.4
// @description 对起点的vip小说自动搜索笔趣阁,要设置滚动模式,自动加载形式,支持手机和网页
// @author JucyZhu
// @match https://m.qidian.com/book/*
// @match https://read.qidian.com/chapter/*
// @match https://vipreader.qidian.com/chapter/*
// @require https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js
// @connect www.xbiquge.la
// @connect www.42zw.com
// @connect www.shuquge.com
// @connect www.20xs.cc
// @connect www.znlzd.com
// @connect www.bqg999.cc
// @connect www.bqg99.cc
// @connect www.nuomi99.com
// @connect www.nuomi9.com
// @connect www.72wx.com
// @run-at document-end
// @grant GM_xmlhttpRequest
// ==/UserScript==
(function() {
'use strict';
// Your code here...
// 声明全局参数
// ===== 自定义站点规则 =====
const sites = [
// 详细版规则示例。注:该网站已无法访问。
{ //基本信息
siteName: "72文学",
URL: "https://www.72wx.com",
urlUpdata: false,
searchURL: "https://www.72wx.com/search.php?keyword=",
method: "GET",
formData: "keyword=",
needName: true,
bookName: "#nr td a:first",
authorName: "#nr td:eq(2)",
chapters: "#list dl dd a:gt(8)",
contentSplit: "<br><br>", //章节分段方式
content: "#content",
removeList:[/72文学/,/www./]
},
{ //基本信息
siteName: "糯米小说网",
URL: "https://www.nuomi99.com",
urlUpdata: false,
searchURL: "https://www.nuomi99.com/web/search.php?q=",
method: "GET",
formData: "q=",
needName: true,
bookName: ".s2 a",
authorName: ".s4:gt(0)",
chapters: "#list dl dd a:gt(11)",
contentSplit: "<br><br>", //章节分段方式
content: "#content",
removeList:[/www./]
},
{ //基本信息
siteName: "书趣阁",
URL: "http://www.shuquge.com/",
urlUpdata: true,
searchURL: "http://www.shuquge.com/search.php",
method: "POST",
formData: "s=6445266503022880974&searchkey=",
needName: false,
bookName: ".bookname a",
authorName: ".author",
chapters: ".listmain dl a:gt(11)",
contentSplit: "<br><br>", //章节分段方式
content: "#content",
removeList:[/www./]
},
{ //基本信息
siteName: "新笔趣云",
URL: "https://www.20xs.cc",
urlUpdata:false,
searchURL: "https://www.20xs.cc/searchbook.php?search_key=",
method: "GET",
formData: "search_key=",
needName: true,
bookName: "strong a",
authorName: "#li1 .name span:odd",
chapters: "#list dl a",
contentSplit: "node", //章节分段方式
content: "#content p",
removeList:[/www./]
},
{ //基本信息
siteName: "新笔趣阁", // 站点名字... (可选)
URL: "http://www.xbiquge.la",
urlUpdata:false,
searchURL: "http://www.xbiquge.la/modules/article/waps.php", //搜索相关
method: "POST", //请求方式
formData: "searchkey=", //请求数据
needName: false,
bookName: "tbody tr .even a", //解析搜索结果相关
authorName: "tbody tr .even:odd",
chapters: "#list dl a", //解析目录列表相关
contentSplit: "<br><br>", //章节分段方式
content: "#content",//解析章节内容
removeList:[/www./] //去插入式广告
},
{ //基本信息
siteName: "999笔趣阁",
URL: "https://www.bqg999.cc/",
urlUpdata:false,
searchURL: "https://www.bqg999.cc/s.php?q=",
method: "GET",
formData: "q=",
needName: true,
bookName: ".bookname a",
authorName: ".author",
chapters: ".listmain dd a",
contentSplit: "<br><br>", //章节分段方式
content: "#content",
removeList:[/www./]
}
];
var data = {
book: {},
currentChapter: {},
chapters: [],
isApp: false
},
replaceList = [/http:/, /笔趣阁/, /shuquge/, /书友群/, /书趣阁/],
chapterNum = 0,
first_time = true,
lock = true,
siteId = 0,
show = false;
//脚本更新data获取书籍信息
getBookContents();
//滚动事件
$(window).scroll(function() {
if (data.isApp) {
show = ($(".read-article .read-section").last().offset().top - $(document).scrollTop() < $(
window).height());
} else {
show = ($("#j_chapterBox .text-wrap:last").offset().top - $(document).scrollTop() < $(window)
.height());
}
if (($(window).scrollTop() * 1.05 > $(document).height() - $(window).height()) && show && lock) {
lock = false;
loadbook();
}
});
function loadbook() {
updata();
//更新data
if (chapterNum > 3) {
if (data.isApp) {
$(".read-section").first().remove()
chapterNum = $(".read-section").length
} else {
$(".text-wrap").first().remove()
chapterNum = $(".text-wrap").length
}
}
if (data.currentChapter.vipState == 1 && chapterNum <= 3) {
updataCurrentChapter(data.currentChapter.id + 1)
//console.log(data.currentChapter)
insertCurrentVipContents();
}
};
//根据当前章节名称,如果是vip则从笔趣阁获取内容资源并插入
function insertCurrentVipContents() {
//根据找到的当前章节url获取说内容并解析
console.log("------正在请求《" + data.currentChapter.chapterName + "》的内容------")
var href = data.currentChapter.href;
GM_xmlhttpRequest({
method: "GET",
url: href,
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
},
data: "",
onload: function(response) {
//console.log("请求成功");
insertChapter(parseContent(response.responseText))
},
onerror: function(response) {
console.log("请求失败: href: " + href);
}
})
};
//更新vip状态和显示章节数
function updata() {
//有没有到vipstate==0 &&(登录(不可用)按钮,订阅按钮长度大于0(有.btn-primary)
//或者.j_subscribeBtn vip章节全部订阅和订阅本章按钮长度大于0
//或者发现.w-all前往vip章节长度大于0)
if (data.currentChapter.vipState == 0) {
if ($(".btn-primary").length > 0) {
//手机版
data.currentChapter.vipState = 1;
$(".btn-primary").remove();
findLastChapter()
} else if ($(".j_subscribeBtn").length > 0 || $(".w-all").length > 0) {
//网页版
data.currentChapter.vipState = 1;
findLastChapter()
//updataCurrentChapter(data.currentChapter.id + 1)
$(".w-all").remove();
}
//findLastChapter()
} else if (data.currentChapter.vipState == 1) {
if (data.isApp) {
chapterNum = $(".read-section").length
//findLastChapter()
} else {
chapterNum = $(".text-wrap").length
//findLastChapter()
}
}
};
function getBookChapterInfor() {
if (typeof(g_data.book) == "undefined") {
//说明是电脑网页端
data.book.bookName = g_data.bookInfo.bookName;
data.book.authorName = g_data.bookInfo.authorName;
data.currentChapter.chapterName = $(".j_chapterName:last span:first").text();
data.currentChapter.vipState = g_data.chapter.vipStatus;
data.currentChapter.contentList = [];
data.currentChapter.id = 0;
data.isApp = false;
} else {
//手机网页端
data.book.bookName = g_data.book.bookName;
data.book.authorName = g_data.book.authorName;
data.currentChapter.chapterName = g_data.chapter.chapterName;
data.currentChapter.vipState = g_data.chapter.vipStatus;
data.currentChapter.contentList = [];
data.currentChapter.id = 0;
data.isApp = true;
}
return data;
};
//寻找匹配目录
function findLastChapter() {
//遍历目录找到当前目录的url
var chapter = "";
if (data.isApp) {
data.currentChapter.chapterName = $(".read-section h3").last().text()
} else {
data.currentChapter.chapterName = $(".text-wrap:last h3 span:first").text()
}
var current_chapter = data.currentChapter.chapterName;
if (data.chapters.length > 0) {
console.log("------正在查找阅读到的最新章节------")
for (var i = 0, len = data.chapters.length; i < len; i++) {
chapter = data.chapters[i].name;
var c = chapter.replace(/\s/g, "").replace(/[::()()]/, "")
var cu = current_chapter.replace(/\s/g, "").replace(/[::()()]/, "")
if (cu === c || cu.indexOf(c) != -1 || c.indexOf(cu) != -1) {
console.log(data.chapters[i])
updataCurrentChapter(i);
break;
} else {
updataCurrentChapter(-1);
}
}
} else {
updataCurrentChapter(-1);
console.log("章节目录没有解析到");
}
//return data.currentChapter.id
};
function updataCurrentChapter(id) {
if (id > -1) {
data.currentChapter.id = id;
data.currentChapter.chapterName = data.chapters[id].name;
data.currentChapter.href = data.chapters[id].href;
} else {
data.currentChapter.id = id;
data.currentChapter.chapterName = "ERROR";
data.currentChapter.href = "www.baidu.com";
}
}
//根据章节名获取笔趣阁的目录列表,并赋值给data.chapters
function getBookContents() {
//从当前页面获取小说名称和当前章节
var config = sites[siteId]
getBookChapterInfor();
//仅第一次运行
//console.log(data.book.booName);
console.log("------开始从*****" + config.siteName + "*****搜索《 " + data.book.bookName + " 》 ------");
if (config.needName) {
config.searchURL = config.searchURL + data.book.bookName
}
runAsync(config.searchURL, config.method, config.formData + data.book.bookName).then((
result) => {
//bookname,authorName ==>搜索===>解析==>href==>请求==>response
function getTitleAuthorList(result) {
//console.log(result.responseText);
var $html = $('<div></div>').html(result.responseText);
var $table = $($html);
var nameList = $(config.bookName, $table),
authorList = $(config.authorName, $table),
href = "";
//console.log("nameList", nameList);
//console.log("authorList", authorList);
//console.log($(nameList[0]).text() + "-----" + $(authorList[0]).text())
for (var i = 0, len = nameList.length; i < len; i++) {
if (data.book.bookName == $.trim($(nameList[i]).text()) && (
data.book.authorName == $.trim($(authorList[i]).text()) ||
$.trim($(authorList[i]).text()).indexOf(data.book.authorName) != -1)) {
//console.log($(nameList[i]).text() + "-----" + $(authorList[i]).text())
//console.log(nameList[i])
href = $(nameList[i]).attr("href");
//href = $(nameList[i]).href;
//没有http 说明url要拼接
//console.log("href", href)
if (href.indexOf("http") == -1) {
href = config.URL + href
};
//console.log("href", href)
break;
}
}
if (nameList.length == 0 || href == "") {
console.log("------从*****" + config.siteName + "*****搜索《 " + data.book.bookName +
" 》 失败------");
siteId = siteId + 1;
if (siteId < sites.length) {
getBookContents()
} else {
console.log("------未能找到小说,请继续完善地址池------");
}
}
if (config.urlUpdata) {
config.URL = href.replace("index.html", "")
}
return runAsync(href);
}
return getTitleAuthorList(result);
}).then((response) => {
//response==>解析==>目录列表==>保存到data==>寻找匹配的章节
console.log("------开始从response解析目录-------- ");
function getChapterNameHref(response) {
var $html = $('<div></div>').html(response.responseText);
var $table = $($html);
var chapters = $(config.chapters, $table);
//console.log(chapters);
for (var i = 0, len = chapters.length; i < len; i++) {
var chapterTmp = {
name: "",
href: ""
};
chapterTmp.name = $(chapters[i]).text();
chapterTmp.href = config.URL + $(chapters[i]).attr("href");
//chapterTmp.href = $(chapters[i]).href;
//console.log(chapterTmp);
data.chapters.push(chapterTmp);
}
//寻找匹配的章节
//console.log(data.chapters)
findLastChapter();
if (data.currentChapter.id != -1) {
//console.log(data.chapters[data.currentChapter.id].name)
return runAsync(data.chapters[data.currentChapter.id].href);
} else {
console.log("目录没有匹配")
return runAsync(data.chapters[0].href);
}
}
return getChapterNameHref(response);
}).then((response) => {
//response==>解析==>章节内容==>保存到data.currentChapter.contentList==>寻找匹配的章节
//console.log(response.responseText)
var c = parseContent(response.responseText)
if (($(".j_subscribeBtn").length > 0 || $(".btn-primary").length > 0) && c.length > 0) {
insertChapter(c);
}
})
};
function parseContent(text) {
var config = sites[siteId]
var $html = $('<div></div>').html(text);
var $content = $(config.content, $html);
//根据config.contentSplit进行不同的读取方式
var contents = []
switch (config.contentSplit) {
case "<br><br>":
$content = $content[0].childNodes
for (var i = 0, len = $content.length; i < len; i++) {
var t = $($content[i]).text();
//去掉包含不必要的字符段落
if (t == "" || t == "\n" || t == "chaptererror();") {
continue
}
//检查插入广告
for (var k = 0, len2 = config.removeList.length; k < len2; k++) {
if(config.removeList[k].test(t)) {
var arr = [t.lastIndexOf("。"), t.lastIndexOf("”"), t.lastIndexOf("?"), t.lastIndexOf("!")];
arr.sort(function(a,b){return a - b;});
var max=arr[arr.length - 1];
t=t.substring(0,max+1);
break;
}
}
//检查段落广告
var pd = false;
for (var j = 0, len1 = replaceList.length; j < len1; j++) {
pd = pd || replaceList[j].test(t);
}
if (!pd) {
contents.push(t);
}
}
break;
case "node":
for (var i1 = 0, lent = $content.length; i1 < lent; i1++) {
contents.push($content[i1].innerText);
}
break;
default:
console.log("未设置 " + config.contentSplit + " 的解析方法")
}
if (contents.length == 0) {
console.log(config.siteName + "----未解析到章节内容,自动换源!!!!!!!")
siteId = siteId + 1;
getBookContents()
}
data.currentChapter.contentList = contents
return contents
}
// 插入文章
function insertChapter(contents) {
var section, paragraph, p = "",
i = 0,
mlen = -1;
if (data.isApp) {
//手机中插入
chapterNum = $(".read-section").length
section = $(".read-article .read-section").last();
$(".read-article").append(section.clone());
section = $(".read-article .read-section").last();
paragraph = $("p", section).first();
$(".btn-primary", section).remove();
$(".read-rss-auto", section).remove();
$("p", section).remove();
$("h3", section).text(data.currentChapter.chapterName);
for (i = 0, mlen = contents.length; i < mlen; i++) {
p = contents[i];
paragraph.text(p);
section.append(paragraph.clone());
}
} else {
chapterNum = $(".text-wrap").length
//web中插入
section = $("#j_chapterBox .text-wrap:last");
$("#j_chapterBox").append(section.clone());
section = $("#j_chapterBox .text-wrap:last");
paragraph = $(".read-content p:first", section);
$(".vip-limit-wrap", section).remove();
$(".admire-wrap", section).remove();
$(".read-content p", section).remove();
$("h3:first span:first", section).text(data.currentChapter.chapterName);
for (i = 0, mlen = contents.length; i < mlen; i++) {
p = contents[i];
paragraph.text(p);
$(".read-content", section).append(paragraph.clone());
}
}
console.log("------已经插入<<" + data.chapters[data.currentChapter.id].name + ">>------")
lock = true;
};
function runAsync(url, send_type = "GET", data_ry = "") {
if (url.length>0) {
console.log("请求数据: url: " + url + " method: " + send_type + " data: " + data_ry);
var p = new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: send_type,
url: url,
headers: {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.57",
"Content-Type": "application/x-www-form-urlencoded"
},
data: data_ry,
onload: function(response) {
resolve(response);
},
onerror: function(response) {
console.log("请求失败: url: " + url + " method: " + send_type +
" data: " +
data_ry);
reject("请求失败: url = " + url);
}
});
})
return p;
}else{
var p = null;
return p;
}
};
})();