// ==UserScript==
// @name 笔趣阁优化
// @namespace https://gitee.com/linhq1999/OhMyScript
// @version 5.2
// @description 专注阅读
// @author LinHQ
// @match http*://www.shuquge.com/*.html
// @exclude http*://www.shuquge.com/*index.html
// @match http*://www.sywx8.com/*.html
// @match http*://www.biqugetv.com/*.html
// @match http*://www.bqxs520.com/*.html
// @match https://www.dshfood.net/*.html
// @grant GM_addStyle
// @grant GM_openInTab
// @grant GM_xmlhttpRequest
// @require https://greasyfork.org/scripts/427726-gbk-url-js/code/GBK_URLjs.js?version=953098
// @inject-into auto
// @license MIT
// @downloadURL https://update.greasyfork.icu/scripts/434661/%E7%AC%94%E8%B6%A3%E9%98%81%E4%BC%98%E5%8C%96.user.js
// @updateURL https://update.greasyfork.icu/scripts/434661/%E7%AC%94%E8%B6%A3%E9%98%81%E4%BC%98%E5%8C%96.meta.js
// ==/UserScript==
'use strict';
/** 配置示例
* 建议在定制 search 函数时, rq 函数始终把参数写全
* "sites": [
* {
* "desc": "shuquge", 网站链接关键字
* "url": "https://....", 网站首页链接
* "main": "div.reader", 主要部分选择器
* "title": ".reader h1", 标题选择器
* "txt": "#content", 文字部分选择器
* "toc": "dd a", 目录链接选择器
* "tocJump": 12, 跳过前面多少章
* "filter": ["div.header", "div.nav", "div.link"], 带有此选择器的元素将被删除
* "txtfilter": ["shuqu"] 带有此关键字的行将被删除
* "funcFilter"?: () => void, 自定义过滤器
* "nodash"?: boolean, 判断是否应该在书籍详情页链接后加额外的斜杠
* "search"?: (keywords: string, baseurl:string) => Promise 搜索行为
* }
* ]
*/
(() => {
// 缺省值,一般不用修改
const lineHeight = 1.3;
// const defaultFont = "楷体";
const defaultFont = "Source Han Sans SC VF";
let C = {
"sites": [
{
"desc": "shuquge",
"url": "https://www.shuquge.com/",
"main": "div.reader",
"title": ".reader h1",
"txt": "#content",
"toc": "dd a",
"tocJump": 12,
"filter": [
"div.header", "div.nav", "div.link", "img",
"#coupletleft", "#coupletright", "#HMRichBox"
],
"txtfilter": ["shuqu"],
"funcFilter": () => { var _a, _b; return (_b = (_a = fd(document, "#content")) === null || _a === void 0 ? void 0 : _a.previousSibling) === null || _b === void 0 ? void 0 : _b.remove(); }
},
{
"desc": "sywx",
"url": "https://www.sywx8.com/",
"main": "div#container",
"title": "div>h1",
"toc": "li a",
"tocJump": 0,
"txt": "div#BookText",
"filter": ["div.top", ".link.xb", "#footer"],
"txtfilter": ["最快更新", "松语", "本章完", "本章未完"],
// javascript 不支持 gbk 的 uri 编码,所以无法实现
// 但是用 gbk.js 就不一样了
"search": async (keywords, baseurl) => {
let links = [];
let doc = await rq({
"url": `https://www.sywx8.com/modules/article/search.php?searchkey=${$URL.encode(keywords)}`
}, 8000, "GBK");
for (let a of doc.querySelectorAll(".c_row .c_subject a")) {
// 这个网站比较特殊,链接默认是完整的
links.push({ "title": `(sywx) ${a.textContent}`, "href": attr(a, "href") });
}
return links;
}
},
{
"desc": "bqxs",
"url": "http://www.bqxs520.com/",
"main": ".box_con",
"title": "div.content_read h1",
"toc": "#list dd a",
"tocJump": 9,
"txt": "#content",
"filter": [".ywtop", ".header", ".nav", ".bottem1", ".lm", "#page_set", ".bookname~.box_con"],
"txtfilter": ["请记住本书", "http"],
"search": async (keywords, baseurl) => {
let links = [];
let doc = await rq({
"method": "POST",
"headers": { "Content-Type": "application/x-www-form-urlencoded" },
"url": encodeURI(`http://www.bqxs520.com/case.php?m=search`),
"data": `&key=${encodeURI(keywords)}`
}, 7000, "UTF-8");
for (let a of doc.querySelectorAll(".l .s2 a")) {
links.push({ "title": `(bqxs) ${a.textContent}`, "href": concatURL(baseurl, attr(a, "href")) });
}
return links;
}
},
{
"desc": "biqugetv",
"url": "https://www.biqugetv.com/",
"main": ".box_con",
"title": "div.content_read h1",
"toc": "#list dd a",
"tocJump": 0,
"txt": "#content",
"filter": [".ywtop", ".header", ".nav", ".bottem1", ".lm", "#page_set"],
"txtfilter": [],
"search": async (keywords, baseurl) => {
let links = [];
let doc = await rq({
"url": encodeURI(`https://www.biqugetv.com/search.php?keyword=${keywords}`)
}, 6000, "UTF-8");
for (let a of doc.querySelectorAll("h3 a")) {
links.push({ "title": `(biqugetv) ${a.textContent}`, "href": concatURL(baseurl, attr(a, "href")) });
}
return links;
}
},
{
"desc": "dshfood",
"url": "https://www.dshfood.net/",
"main": ".box_con",
"title": "div.content_read h1",
"toc": "#list dd a",
"tocJump": 9,
"txt": "#content",
"filter": [".ywtop", ".header", ".nav", ".bottem1", "#page_set", "#content>div"],
"txtfilter": ["笔趣阁"],
"nodash": true,
"funcFilter": () => document.querySelectorAll("img")
.forEach(e => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.remove(); }),
"search": async (keywords, baseurl) => {
let links = [];
let doc = await rq({
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"referer": "https://www.dshfood.net/so/"
},
"url": "https://www.dshfood.net/so/",
// 鉴于使用了 GBK 进行编码,不能再使用 URLSearchParams
"data": `?searchtype=articlename&searchkey=${$URL.encode(keywords)}&submit=`
}, 6000, "GBK");
for (let a of doc.querySelectorAll(".line a.blue")) {
links.push({ "title": `(dshfood) ${a.textContent}`, "href": concatURL(baseurl, attr(a, "href")) });
}
return links;
}
}
],
"states": {
"fontSize": 16,
"lineHeight": 16 * lineHeight,
"toc": false,
"flow": false
},
"style": `
body {
background-color: #EAEAEF !important;
}
.bqg.inject.win {
width: 55vw !important;
min-width: 600px;
border: 2px double gray !important;
border-radius: 8px;
}
.bqg.inject.txt {
font-family: Calibri,'${defaultFont}',serif!important;
background-color: #EAEAEF !important;
padding: 0.5em 1em !important;
margin: 0.5em auto !important;
width: auto !important;
white-space: pre-wrap;
}
.bqg.inject.title {
color: black;
background-color: #EAEAEF;
font-family: Calibri,'${defaultFont}',serif!important;
cursor: pointer !important;
}
.bqg.inject.title:hover {
color: #0258d8 !important;
}
.hq.inject.toc {
font-family: Calibri,sans-serif;
width: 275px;
position: fixed;
top: 30px;
left: 8px;
/*目录默认是关闭的*/
transform: translateX(-300px);
opacity: 0;
padding: 5px;
display: flex;
flex-flow: column;
box-shadow: #7b7b7b 5px 4px 5px;
transition-property: transform, box-shadow, opacity;
transition-duration: .5s;
transition-timing-function:cubic-bezier(0.35, 1.06, 0.83, 0.99);
background: rgb(246 246 246 / 60%);
backdrop-filter: blur(2px);
border-radius: 8px;
}
.hq.inject ul {
height: 280px;
width: 100%;
/*offsetTop 计算需要*/
position:relative;
overflow: auto;
}
.hq.inject ul li {
cursor: pointer;
margin: 2px;
width: 95%;
padding: 1px 4px;
font-size: 12px;
border-radius: 4px;
}
.hq.inject ul li:hover {
background: #0258d8;
color: #f6f6f6;
}
.hq.inject.toc>h3 {
font-size: 1.1rem;
font-weight: bold;
border-radius: 2px;
align-self: center;
cursor: pointer;
margin: 4px 0 8px 0;
}
.hq.inject.toc>h3:hover {
color: #ffa631 !important;
}
.hq.inject.search {
font-family: Calibri,sans-serif;
width: 275px;
position: fixed;
top: 30px;
padding: 5px;
display: flex;
flex-flow: column;
transition: right 0.5s cubic-bezier(0.35, 1.06, 0.83, 0.99);
background: rgb(246 246 246 / 60%);
border-radius: 8px;
}
.hq.inject.search input {
margin: 8px auto;
width: 95%;
}
`
};
// 查询已经保存的字体信息
let savedStates = localStorage.getItem("bqg_cfg");
// 检查是否存在已有设置且和当前版本相符
let states;
if (savedStates === null) {
states = C.states;
console.warn("当前状态已保存");
}
else {
let cfg = JSON.parse(savedStates);
let defaultStates = Object.keys(C.states);
let cfg_ = Object.keys(cfg);
let useSaved = true;
// 检查键是否匹配
if (defaultStates.length == cfg_.length) {
for (let key of Object.keys(cfg)) {
if (!defaultStates.includes(key)) {
useSaved = false;
break;
}
}
}
else {
useSaved = false;
}
if (useSaved) {
states = cfg;
}
else {
states = C.states;
console.warn("检测到版本变化,状态已重置");
}
}
// 检测当前的网址,应用对应的设置
let tmp = C.sites.filter(site => document.URL.includes(site.desc));
if (tmp.length == 0) {
console.warn("没有匹配的设置,脚本已终止!");
return;
}
let currentSite = tmp[0];
// 完成样式注入
GM_addStyle(C.style);
/**
* 保存交互式状态
*/
function saveStates() {
localStorage.setItem("bqg_cfg", JSON.stringify(states));
}
/**
* 上一章,同时移除所有 flow 拼接结果
*/
function prevChapter() {
var _a;
(_a = fd(document, "a", "上一")) === null || _a === void 0 ? void 0 : _a.click();
}
/**
* 下一章,同时移除所有 flow 拼接结果
*/
function nextChapter() {
var _a;
(_a = fd(document, "a", "下一")) === null || _a === void 0 ? void 0 : _a.click();
}
/**
* 异步,向下拼页
* 绑定到事件上时务必注意重复触发的情况
*/
async function concatNextCh() {
var _a;
let next = fd(document, "a", "下一");
let prev = fd(document, "a", "上一");
let currentText = fd(document, currentSite.txt);
try {
let doc = await rq({ url: next === null || next === void 0 ? void 0 : next.href });
let text = fd(doc, currentSite.txt);
// console.log(text.textContent)
// 更好的性能
currentText.insertAdjacentHTML("beforeend", "