Greasy Fork

Greasy Fork is available in English.

起点小说vip自动换源

对起点的vip小说自动搜索笔趣阁,要设置滚动模式,自动加载形式,支持手机和网页

当前为 2021-04-08 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         起点小说vip自动换源
// @namespace    http://tampermonkey.net/
// @version      2.2
// @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
// @run-at       document-end
// @grant        GM_xmlhttpRequest
// ==/UserScript==
(function() {
	'use strict';
	// Your code here...
	// 声明全局参数
	// ===== 自定义站点规则 =====
	const sites = [
		// 详细版规则示例。注:该网站已无法访问。
		{ //基本信息
			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: "\n\n", //章节分段方式
			content: "#content",
			replace: "",
			slice:[1,-1]
		},
		// { //基本信息 存在反爬虫
		// 	siteName: "ZW笔趣阁",
		// 	URL: "http://www.42zw.com/",
		// 	urlUpdata:false,
		// 	searchURL: "http://www.42zw.com/search?keyword=",
		// 	method: "GET",
		// 	formData: "keyword=",
		// 	needName: true,
		// 	bookName: ".s2 a",
		// 	authorName: ".s4 a",
		// 	chapters: "#list dl a:gt(11)",
		// 	contentSplit: "node", //章节分段方式
		// 	content: "#content p:gt(0)",
		// 	replace: "",
		// 	slice:[1]
		// },
		{ //基本信息
			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",
			replace: "",
			slice:[]
		},
		{ //基本信息
			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: "\n\n", //章节分段方式
			content: "#content", //解析章节内容
			replace: "#content p",
			slice:[0,-1]
		}
	];
	var data = {
			book: {},
			currentChapter: {},
			chapters: [],
			isApp: false
		},
		chapterNum = 0,
		first_time = true,
		lock = true,
		siteId = 2,
		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) {
					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要拼接
						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[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==>寻找匹配的章节
			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 "\n\n":
				// contents = $content.text().replace($(config.relace, $html).text(), "").split(
				// 	"\n\n");
				contents = $content.text().split("\n\n");
				break;
			case "node":
				for (var i = 0, len = $content.length; i < len; i++) {
					//contents.push($($content[i]).text());
					contents.push($content[i].innerText);
				}
				break;
			default:
				console.log("未设置 " + config.contentSplit + " 的解析方法")				
		}
		if (contents.length == 0) {
			console.log("未解析到章节内容,自动换源!!!!!!!")
			siteId = siteId + 1;
			getBookContents()
		}
		console.log("contents:",contents)
		var s = sites[siteId].slice;
		if(s.length == 1){
			contents = contents.slice(s[0])
		}else{
			contents = contents.slice(s[0],s[1])
		}
		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 = "") {
		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;
	};

})();