// ==UserScript==
// @name 98搜索增强
// @version 1.2.4
// @description 在搜索页进行搜索结果过滤、自动翻页、帖子预览,划词搜索
// @author etai2019
// @license GPL-3.0 License
// @match https://*.sehuatang.net/*
// @match https://*.sehuatang.org/*
// @match https://*.30fjp.com/*
// @match https://*.18stm.cn/*
// @match https://*.jq2t4.com/*
// @match https://*.xo6c5.com/search.php?*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM_registerMenuCommand
// @run-at document-end
// @require https://update.greasyfork.org/scripts/447533/1214813/findAndReplaceDOMText%20v%20046.js
// @namespace etai2019
// ==/UserScript==
const clearCfg = false,
clearCfgDebug = false;
// 初始化参数
if (clearCfgDebug || (clearCfg && GM_getValue('version') != GM_info.script.version) ){
for (let i of GM_listValues()) {
GM_deleteValue(i)
}
GM_setValue('version', GM_info.script.version)
}
// 初始化 setting
var default_settings = {
"AutoScroll": {
"Description": "自动翻页",
"Enable": true,
},
"Includes": {
"Description": "只看关键词",
"Keywords": ["综合讨论区","高清中文字幕"],
},
"Excludes": {
"Description": "排除关键词",
"Keywords": ["资源出售","求片问答","内容隐藏","搬运","SHA1"],
},
"Banned": {
"Description": "关键词黑名单,作用相当于排除关键词,但不会出现在搜索结果的可选框里",
"Keywords": [],
},
"SelectSearch": {
"Description": "划词搜索",
"Enable": true,
},
"PreviewImage" : {
"Enable": false,
"Width": "90vw",
"Height": "50vh",
},
"ScaleImageByWheel": {
"Description": "滑鼠标缩放",
"Unit": 0.3,
"Enable": true
},
"Highlight": {
"Description": "高亮关键词",
"Keywords": "明里",
"Enable": false,
}
};
const settings = Object.assign({}, default_settings, GM_getValue("_98settings") || {});
// 初始化 脚本内部setting
var default_settings2 = {
"ExcludedValues": [],
"IncludedValues": [],
}
const settings2 = Object.assign({}, default_settings2, GM_getValue("_98settings2") || {});
// 添加样式
GM_addStyle(`
.highlight {
font-size: 1.2em;
font-weight: bolder;
background-color: yellow;
}
.slst {
width: 1200px;
margin-left: 30px;
}
.s2-sav-menu{
font-family: Microsoft YaHei,sans-serif;
position:fixed;
display: block;
text-align: left;
color: #000;
background:rgba(255,255,255,.8);
backdrop-filter: blur(5px);
border-radius: 4px;
padding:6px 12px 10px 9px;
/* margin-top: -2px; */
z-index: 99999;
font-size: 14px;
max-width: 600px;
box-shadow: 4px 4px 12px #ccc, -1px -1px 5px #eee;
border-top: 2px solid #fff;
border-left: 2px solid #fff;
transform:scale(1);
transition:0.2s;
transition-timing-function: ease-out;
animation: savOpenAnim 0.15s;
}
.savlink{
margin: 4px 4px 4px 4px;
border-radius: 4px;
padding: 3px 5px;
background: #fff;
display: inline-block;
transition: 0.2s;
transition-timing-function: ease-out;
box-shadow: -2px -2px 4px rgb(240 240 240), 2px 2px 4px rgb(70 70 70 / 50%);
cursor: pointer;
user-select: none;
}
.savlink:not(.RPdisabled):hover{
background: aliceblue;
box-shadow: -2px -2px 6px rgb(255 255 255 / 50%), 1px 1px 2px rgb(70 70 70 / 50%), inset -2px -2px 6px rgb(255 255 255 / 50%),inset 2px 2px 6px rgb(100 100 100 / 50%);
}
.s2-sav-menu .savlink a{
color:#459df5;
text-decoration:none;
transition:0.4s;
}
.s2-sav-menu .savlink:not(.RPdisabled):hover a {
color: #039cff;
text-shadow: 0 0 #7cfb80;
}
.settings-container {
font-family: Arial;
font-size: 16px;
color: #333;
border: 1px solid #ccc;
padding: 2px;
background-color: #fff;
display: flex;
justify-content: space-between;
}
.checkbox-group {
display: flex;
gap:.5em;
font-family: Arial;
font-size: 16px;
}
.checkbox-group label {
display: block;
}
.like-popup {
width: 30%;
position: fixed;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 999;
background-color: #ddd;
border: 1px solid;
padding: 5px;
}
.like-popup-content{
font-size: 2em;
margin-bottom: 1.5em;
}
.like-popup h5{
font-size: 1.5em;
}
.preview-img {
max-width: 49%;
max-height: 100%;
border: 1px solid;
position: relative;
}
`);
(function() {
'use strict';
// 设置菜单
GM_registerMenuCommand("设置", function() {
var editbox = document.createElement("div");
editbox.id = "sav-editCodeBox";
editbox.style.cssText = "position:fixed;" +
"z-index:99999;" +
"top:50%;left:50%;" +
"transform:translate(-50%,-50%);" +
"background:#ccc;" +
"border-radius:4px;" +
"padding:10px 20px;" ;
editbox.innerHTML = " "+
"<textarea wrap='off' cols='66' rows='20' style='overflow:auto;border-radius:4px;'>" + JSON.stringify(settings, false, 4) + "</textarea>" +
"<br>" +
"<button id='savDebug'>还原默认设置</button> " +
"<button id='savEditBoxCloase' >关闭</button> " +
"<button id='savEditBoxSave' >保存</button>" +
"";
// 还原默认设置
editbox.querySelector("#savDebug").addEventListener("click", function() {
document.querySelector("#sav-editCodeBox textarea").value = JSON.stringify(default_settings, false, 4);
})
// 关闭设置
editbox.querySelector("#savEditBoxCloase").addEventListener("click", function() {
editbox.parentNode.removeChild(editbox);
});
// 保存设置
editbox.querySelector("#savEditBoxSave").addEventListener("click", function() {
var codevalue = document.querySelector("#sav-editCodeBox textarea").value;
var new_settings;
try {
new_settings = JSON.parse(codevalue);
} catch(err){
alert("保存失败,请按照下方提示修改后重新保存\n"+err);
return;
}
GM_setValue("_98settings", new_settings);
editbox.parentNode.removeChild(editbox);
setTimeout(function(){
window.location.reload();
}, 100);
})
document.body.appendChild(editbox);
})
// 高亮关键词
if (settings.Highlight.Enable) {
HighlightKeywords();
}
// 划词搜索
if (settings.SelectSearch.Enable) {
document.onmouseup = SelectSearch;
}
// 搜索增强
var curSite = {}
const isSearchResultPage = window.location.href.includes('search.php');
if (isSearchResultPage) {
SetupNewSearch();
}
// 函数区域
// 搜索增强
function SetupNewSearch() {
// 自动翻页
if (settings.AutoScroll.Enable) {
curSite = {
SiteTypeID: 641,
pageurl: "",
pager: {
forceHTTPS: true,
interval: 500,
nextL: "a.nxt:not([href^=\"javascript\"]) ,a.next:not([href^=\"javascript\"])",
pageE: "#threadlist > ul",
replaceE: ".pg, .pages",
scrollD: 2000,
type: 1
},
pausePage: false,
pageNum: { now: 1, _now: 1 },
}
RegisterAutoScroll();
// 分页放在最上面
const pgDiv = document.querySelector('.pgs');
if (pgDiv != null) {
document.querySelector('.sttl').insertAdjacentElement('afterend', pgDiv);
}
}
// 推广弹窗
const likePopup = document.createElement('div');
likePopup.className = 'like-popup';
likePopup.style.setProperty('display', 'none')
document.body.appendChild(likePopup);
likePopup.innerHTML = `
<div class='like-popup-content'>
<p>好用请给作者评分点赞吧~</p>
<p>(版本大更新,弹窗一次,望理解)</p>
</div>
<h5><a href="forum.php?mod=viewthread&tid=1508541" target="_blank">好的,打开帖子</a></h5>
<h5><a href="javascript:document.querySelector('.like-popup').style.setProperty('display', 'none')">关闭</a></h5>
`;
// 创建多选框组
const exclusionCheckboxGroup = document.createElement('div');
exclusionCheckboxGroup.className = 'checkbox-group';
exclusionCheckboxGroup.appendChild(ele('<span>排除</span>'));
for (const keyword of settings.Excludes.Keywords) {
exclusionCheckboxGroup.appendChild(ele(`<label><input type="checkbox" class="exclusion" value="${keyword}"/>${keyword}</label>`));
}
const inclusionCheckboxGroup = document.createElement('div');
inclusionCheckboxGroup.className = 'checkbox-group';
inclusionCheckboxGroup.appendChild(ele('<span>只看</span>'));
for (const keyword of settings.Includes.Keywords) {
inclusionCheckboxGroup.appendChild(ele(`<label><input type="checkbox" value="${keyword}"/>${keyword}</label>`));
}
// 当多选框选项更改时,将所选值保存到脚本中
exclusionCheckboxGroup.querySelectorAll('input[type="checkbox"]').forEach((checkbox) => {
checkbox.addEventListener('change', (event) => {
const excludedValues = Array.from(exclusionCheckboxGroup.querySelectorAll('input[type="checkbox"]:checked')).map((checked) => checked.value);
settings2.ExcludedValues = excludedValues;
SaveSettings2();
// 移除搜索结果
RemoveSearchResutls();
});
});
inclusionCheckboxGroup.querySelectorAll('input[type="checkbox"]').forEach((checkbox) => {
checkbox.addEventListener('change', (event) => {
const includedValues = Array.from(inclusionCheckboxGroup.querySelectorAll('input[type="checkbox"]:checked')).map((checked) => checked.value);
settings2.IncludedValues = includedValues;
SaveSettings2();
// 移除搜索结果
RemoveSearchResutls();
});
});
// 读取所选值
const excludedValues = settings2.ExcludedValues;
const includedValues = settings2.IncludedValues;
// 恢复之前的选择
excludedValues.forEach((selectedValue) => {
const checkboxElement = exclusionCheckboxGroup.querySelector(`input[value="${selectedValue}"]`);
if (checkboxElement) {
checkboxElement.checked = true;
}
});
includedValues.forEach((selectedValue) => {
const checkboxElement = inclusionCheckboxGroup.querySelector(`input[value="${selectedValue}"]`);
if (checkboxElement) {
checkboxElement.checked = true;
}
});
// 超级模式快捷方式
const turboModeSwitch = ele(`<div><label><input type="checkbox" value="超级模式"/>超级模式</label></div>`);
turboModeSwitch.querySelector(`input`).checked = settings.PreviewImage.Enable;
turboModeSwitch.querySelector(`input`).addEventListener('change', (event) => {
settings.PreviewImage.Enable = !settings.PreviewImage.Enable;
GM_setValue("_98settings", settings);
setTimeout(function(){
window.location.reload();
}, 100);
});
// 添加页面元素
const searchForm = document.querySelector('.searchform');
const settingsContainer = document.createElement('div');
settingsContainer.className = 'settings-container';
searchForm.appendChild(settingsContainer);
// 将多选框组添加到页面中
const keywordSettings = document.createElement('div');
keywordSettings.appendChild(exclusionCheckboxGroup);
keywordSettings.appendChild(inclusionCheckboxGroup);
settingsContainer.appendChild(keywordSettings);
// 将超级模式快捷方式添加到页面中
settingsContainer.appendChild(turboModeSwitch)
// 初始时移除搜索结果
RemoveSearchResutls();
}
// 高亮关键词
function HighlightKeywords() {
const oRegex = new RegExp(`${settings.Highlight.Keywords}`, "gi");
findAndReplaceDOMText(document.body, {
find: oRegex,
wrap: 'avem',
wrapClass: 'highlight'
});
// 创建观察者对象
var observerConfig = {childList: true, characterData: true ,subtree:true,};
var observer = new window.MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.target.innerText.length < 5) {
return;
}
if(IsContentDom(mutation.target)) {
return;
}
if (mutation.target.innerText?.search(oRegex) <= -1) {
return;
}
observer.disconnect(); // 关闭对 dom 的监听
console.log(mutation.target);
// findAndReplaceDOMText(document.body, {
// find: new RegExp(`${settings.Highlight.Keywords}`, "gi"),
// wrap: 'avem',
// wrapClass: 'highlight'
// });
observer.observe(document.body, observerConfig); // 开启对 dom 的监听
})
});
// observer.observe(document.body, observerConfig)
}
// 检查是否为包含正文的Dom
function IsContentDom(startDom){
const RE_Exclude_className = /(?<!file)name|auth|user|(?<!home)code|^pstatus$|(?<!_tl_|ql-)editor|time|sav-id|sidebar|menu|TbwUpd/gi;
if(startDom.classList && startDom.classList.length && startDom.className.match(RE_Exclude_className)){
return true;
}
if(startDom.parentElement && "body" !== startDom.parentElement.nodeName){
return IsContentDom(startDom.parentElement)
} else {
return false
}
}
// 图片预览弹窗
function DisplayPreviewBox(url) {
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: function(response) {
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(response.responseText, "text/html");
var images = Array.from(htmlDoc.querySelectorAll(".zoom")).filter(image => !(image.getAttribute("zoomfile") || image.src || image.getAttribute('file')).includes('static'));
if (!images || images.length == 0) return;
if (images.length > 2) images.length = 2;
var box = document.createElement("div");
document.body.appendChild(box);
box.classList.add("tk_preview");
box.style.cssText = `
width: 99%;
border: 1px solid;
background-color: #ddd;
position: fixed;
top: 50%;
transform: translate(0%, -50%);
zIndex = 99999;
`;
box.addEventListener("click", function() {
document.body.removeChild(box);
});
for (let image of images) {
var preview = document.createElement("img");
box.appendChild(preview);
var src = image.getAttribute("zoomfile") || image.src || image.getAttribute('file');
preview.src = src;
preview.className = "preview-img"
if (settings.ScaleImageByWheel.Enable) {
preview.addEventListener("wheel",ImgScaleWheel);
}
}
}
});
}
// 在搜索结果中直接加载图片
function LoadPreviewsAndLinks(item) {
if (!settings.PreviewImage.Enable) return;
let linkTag = item.querySelector('a');
GM_xmlhttpRequest({
method: "GET",
url: linkTag.href,
onload: function(response) {
const debug = false;
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(response.responseText, "text/html");
var images = Array.from(htmlDoc.querySelectorAll(".zoom")).filter(image => !(image.getAttribute("zoomfile") || image.src || image.getAttribute('file')).includes('static'));
if (!images || images.length == 0) return;
if (images.length > 2) images.length = 2;
let div = document.createElement('div');
item.appendChild(div);
div.style.width = settings.PreviewImage.Width;
div.style.height = settings.PreviewImage.Height;
div.classList.add('tk_preview_div');
for (let image of images) {
var preview = document.createElement("img");
div.appendChild(preview);
const src = image.getAttribute("zoomfile") || image.src || image.getAttribute('file');
preview.src = src;
preview.className = "preview-img"
if (settings.ScaleImageByWheel.Enable) {
preview.addEventListener("wheel",ImgScaleWheel);
preview.addEventListener("click",ImgScaleClick);
}
}
if (debug) {
const code = htmlDoc.querySelector('.blockcode');
if (code != null) {
const magnet = code.querySelector('li').innerText
const magnetA = document.createElement('a');
magnetA.setAttribute('href', magnet);
magnetA.innerText = '🧲';
linkTag.parentNode.appendChild(magnetA);
}
const bt = htmlDoc.querySelector('.attnm');
if (bt != null) {
const btlink = bt.querySelector('a').href;
const btA = document.createElement('a');
btA.setAttribute('target', '_blank');
btA.setAttribute('href', btlink);
btA.innerText = '💾';
linkTag.parentNode.appendChild(btA);
}
}
}
});
}
// 图片缩放
const likePopupLifetimePages = 100;
function ImgScaleWheel(e){
if (!e.target.ImageScale) e.target.ImageScale = 1.0;
if (!window.ImgIndex) window.ImgIndex = 100;
var imageScale = e.target.ImageScale;
if(e.target.tagName == "IMG"){
e.target.style.zIndex = window.ImgIndex++;
if(e.wheelDelta > 0){
imageScale += settings.ScaleImageByWheel.Unit;
// 推广弹窗
const lifetimePages = (GM_getValue("lifetime_pages") ?? 0) + 1;
const likePopupDisplayTimes = GM_getValue("likePopupDisplayTimes") ?? 0;
if (likePopupDisplayTimes == 0 && lifetimePages >= likePopupLifetimePages) {
document.querySelector('.like-popup').style.setProperty('display', 'block');
GM_setValue("likePopupDisplayTimes", likePopupDisplayTimes + 1);
}
GM_setValue("lifetime_pages", lifetimePages);
console.log("lifetime_pages:", lifetimePages);
} else if(e.wheelDelta < 0){
if(imageScale > 1){
imageScale -= settings.ScaleImageByWheel.Unit;
}
// 最小减至1
if(imageScale <= 1){
imageScale = 1.0;
e.target.style = "";
};
}
e.target.style.transform = "scale(" + imageScale +")";
}
e.target.ImageScale = imageScale;
e.preventDefault();
return false;
}
// 取消图片缩放
function ImgScaleClick(e) {
if(e.target.tagName == "IMG"){
if (e.target.ImageScale) {
e.target.ImageScale = 1.0;
}
e.target.style = "";
}
}
// 尝试显示图片预览
function DecorateResultItem(item) {
if (item.styleDone) return;
item.styleDone = true;
// 删除搜索结果文本
let p = item.querySelectorAll('p')[1]
p.style.display = 'none';
// 超级模式直接显示预览
if (settings.PreviewImage.Enable) {
LoadPreviewsAndLinks(item);
return;
}
// 添加预览图片按钮
var button = document.createElement("button");
button.classList.add('tk-preview-button');
button.style.marginRight = "10px";
button.innerHTML = "预览图片";
// 添加按钮点击事件
let linkTag = item.querySelector('a');
button.onclick = function() {
// 获取链接的href属性
DisplayPreviewBox(linkTag.href);
};
linkTag.parentNode.insertBefore(button, linkTag);
}
// 筛选搜索结果
function RemoveSearchResutls() {
// 读取所选值
const excludedValues = settings2.ExcludedValues.concat(settings.Banned.Keywords);
const includedValues = settings2.IncludedValues;
// 获取搜索结果
var items = document.querySelectorAll('.slst li');
// 处理每一个搜索结果
for (let item of items){
const titleText = item.querySelector('a').innerText.toUpperCase();
const forum = item.querySelector('.xi1').innerText;
const preview = item.querySelector('.xg1').nextElementSibling.innerText;
const resultText = titleText + forum + preview;
// 只显示关键词
let shouldShow = includedValues.length == 0 || includedValues.some(word => resultText.includes(word));
if (shouldShow) {
item.style.removeProperty('display');
} else {
item.style.display = "none";
continue;
}
// 排除关键词
let shouldHide = excludedValues.some(word => resultText.includes(word));
if (shouldHide) {
item.style.display = "none";
} else {
item.style.removeProperty('display');
DecorateResultItem(item)
}
}
};
// 监听滚动条事件
function WindowScroll(fn) {
var beforeScrollTop = document.documentElement.scrollTop || document.body.scrollTop
fn = fn || function () {};
// 延时 1 秒执行,避免刚载入到页面就触发翻页事件
setTimeout(function () {
// 避免网页内容太少,高度撑不起来,不显示滚动条而无法触发翻页事件
let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop,
scrollHeight = window.innerHeight || document.documentElement.clientHeight
if (scrollTop === 0 && document.documentElement.scrollHeight === scrollHeight) {
const style = `html, body {min-height: ${document.documentElement.scrollHeight+10}px;}`;
console.log('网页内容太少,高度撑不起来!!', style);
document.documentElement.appendChild(document.createElement('style')).textContent = style;
}
window.addEventListener('scroll', function (e) {
var afterScrollTop = document.documentElement.scrollTop || document.body.scrollTop,
delta = afterScrollTop - beforeScrollTop;
if (delta == 0) return false;
fn(delta > 0 ? 'down' : 'up', e);
beforeScrollTop = afterScrollTop;
}, false);
}, 1000)
}
// 将无缝翻页注册进监听器
function RegisterAutoScroll() {
if (curSite.pager.scrollD === undefined) curSite.pager.scrollD = 2000; // 默认翻页触发线 2000
if (curSite.pager.interval === undefined) curSite.pager.interval = 500; // 默认间隔时间 500ms
curSite.pageUrl = ''; // 下一页URL
WindowScroll(function (direction, e) {
// 下滑 且 未暂停翻页 且 SiteTypeID > 0 时,才准备翻页
if (direction != 'down' || curSite.pausePage || curSite.SiteTypeID == 0) return
let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
let scrollHeight = window.innerHeight || document.documentElement.clientHeight
let scrollD = curSite.pager.scrollD;
if (document.documentElement.scrollHeight <= scrollHeight + scrollTop + scrollD) {
intervalPause();
GoToNextPage(LoadNextPage);
}
});
function intervalPause() {
if (curSite.pager.interval) {
curSite.pausePage = true
setTimeout(function(){curSite.pausePage = false;}, curSite.pager.interval)
}
}
}
// 检查 URL
function GoToNextPage(func) {
if (GetNextPageLink()) {
func(curSite.pageUrl);
}
}
// 通用型获取下一页地址(从 元素 中获取页码)
function GetNextPageLink(css) {
if (!css) css = curSite.pager.nextL;
let next = QueryElement(css);
if (next && next.nodeType === 1 && next.href && next.href.slice(0,4) === 'http' && next.getAttribute('href').slice(0,1) !== '#') {
if (next.href != curSite.pageUrl) {
if (curSite.pager.forceHTTPS && location.protocol === 'https:') {
if (next.href.replace(/^http:/,'https:') === curSite.pageUrl) {
return false
}
curSite.pageUrl = next.href.replace(/^http:/,'https:');
} else {
curSite.pageUrl = next.href;
}
} else {
return false
}
return true
}
return false
}
// 查询单个元素
function QueryElement(selector, contextNode = undefined, doc = document) {
if (!selector) return;
contextNode = contextNode || doc;
return contextNode.querySelector(selector);
}
function CreateDocumentByString(e) {
if (e) {
if ('HTML' !== document.documentElement.nodeName) return (new DOMParser).parseFromString(e, 'application/xhtml+xml');
var t;
try { t = (new DOMParser).parseFromString(e, 'text/html');} catch (e) {}
if (t) return t;
if (document.implementation.createHTMLDocument) {
t = document.implementation.createHTMLDocument('ADocument');
} else {
try {((t = document.cloneNode(!1)).appendChild(t.importNode(document.documentElement, !1)), t.documentElement.appendChild(t.createElement('head')), t.documentElement.appendChild(t.createElement('body')));} catch (e) {}
}
if (t) {
var r = document.createRange(),
n = r.createContextualFragment(e);
r.selectNodeContents(document.body);
t.body.appendChild(n);
for (var a, o = { TITLE: !0, META: !0, LINK: !0, STYLE: !0, BASE: !0}, i = t.body, s = i.childNodes, c = s.length - 1; c >= 0; c--) o[(a = s[c]).nodeName] && i.removeChild(a);
return t;
}
} else console.error('没有找到要转成 DOM 的字符串', e);
}
// 读取下一页内容
function LoadNextPage(url) {
// 读取下一页
GM_xmlhttpRequest({
url: url,
method: 'GET',
overrideMimeType: 'text/html; charset=' + (document.characterSet||document.charset||document.inputEncoding),
headers: {
'Referer': (curSite.noReferer === true) ? '':location.href,
'User-Agent': navigator.userAgent,
'Accept': 'text/html,application/xhtml+xml,application/xml'
},
timeout: 10000,
onload: function (response) {
try {
// console.log('URL:' + url, '最终 URL:' + response.finalUrl, '返回内容:' + response.responseText)
console.log('成功载入下一页:', url, 'Response URL:', response.finalUrl)
ProcessNewPageElems(CreateDocumentByString(response.responseText));
// 筛选搜索结果
RemoveSearchResutls();
// 微移一个像素,这样可以直接用滚轮载入下一页
document.documentElement.scrollTop -= 0.1;
} catch (e) {
console.error('[自动无缝翻页] - 处理获取到的下一页内容时出现问题,请检查!', e, response.responseText);
}
},
onerror: function (response) {
console.log('❌ 获取下一页失败...URL:' + url, response)
},
ontimeout: function (response) {
setTimeout(function(){curSite.pageUrl = '';}, 3000)
console.log('❌ 获取下一页超时,可 3 秒后再次滚动网页重试(或尝试刷新网页)...URL:' + url, response)
}
});
}
// 获取最后一个元素,排除 <script> <style> <link> 标签
function GetLastElement(a) {
if (a.length === 0) return
let b = a.pop();
if (b.tagName === 'SCRIPT' || b.tagName === 'STYLE' || b.tagName === 'LINK') {
return GetLastElement(a);
}
return b
}
// 查询多个元素
function QueryElementsAll(selector, contextNode = undefined, doc = document) {
if (!selector) return [];
contextNode = contextNode || doc;
return [].slice.call(contextNode.querySelectorAll(selector));
}
// 替换元素
function ReplaceNewPageElems(pageE, o = curSite.pager.replaceE, r = curSite.pager.replaceE) {
let oE = QueryElementsAll(o),
rE = QueryElementsAll(r, pageE, pageE);
if (oE.length != 0 && rE.length != 0 && oE.length === rE.length) {
for (let i = 0; i < oE.length; i++) {
oE[i].outerHTML = rE[i].outerHTML;
}
return true
} else {console.log(pageE,oE,rE)}
return false
}
// XHR 后处理结果,插入、替换元素等(适用于翻页类型 1/3/6)
function ProcessNewPageElems(response) {
if (!curSite.pager.insertP) {curSite.pager.insertP = [curSite.pager.pageE, 5]}
let pageE = QueryElementsAll(curSite.pager.pageE, response, response), toE;
if (curSite.pager.insertP[1] === 5) { // 插入 pageE 列表最后一个元素的后面
toE = GetLastElement(QueryElementsAll(curSite.pager.insertP[0]));
}
if (pageE.length > 0 && toE) {
// 插入位置
let addTo = 'afterend';
// 插入新页面元素
if (curSite.pager.insertP[1] === 2 || curSite.pager.insertP[1] === 4 || curSite.pager.insertP[1] === 5) pageE.reverse(); // 插入到 [元素内头部]、[目标本身后面] 时,需要反转顺序
pageE.forEach(function (one) {toE.insertAdjacentElement(addTo, one);});
// 当前页码 + 1
curSite.pageNum.now = curSite.pageNum._now + 1
// 替换待替换元素
if (curSite.pager.replaceE) ReplaceNewPageElems(response);
} else { // 获取主体元素失败
console.error('[自动无缝翻页] 获取主体元素失败...')
}
}
// 划词搜索
function SelectSearch(e) {
if(e.button != 0) return; // 排除非左键点击
if(document.activeElement.tagName.toUpperCase() == "INPUT" || document.activeElement.tagName.toUpperCase() == "TEXTAREA") return; // 排除inpu和textarea内的文本
var selectText = window.getSelection().toString().trim();
if (selectText.length < 2) {
var odiv = document.querySelector(".s2-sav-menu");
if (odiv != null) {
odiv.parentNode.removeChild(odiv);
}
return;
}
if(document.querySelector(".s2-sav-menu")) return; //如果已经存在菜单, 退出
var odiv = CreateSearchPopup(selectText);
var divClientRect = odiv.getBoundingClientRect()
var divWidth = divClientRect.right - divClientRect.left;
odiv.style.left = e.pageX - divWidth/2 - 5 + "px";
odiv.style.top = e.pageY - 5 + "px";
odiv.style.position = "absolute";
document.body.appendChild(odiv);
}
// 创建搜索菜单
function CreateSearchPopup(selectText){
console.log(selectText)
let aPattern = `
<avdivbutton>
<avdiv class='savlink savsehuatang' data-avid=${selectText}> 搜索 </avdiv>
</avdivbutton>
`;
Sehuatang_GetFormHash();
var odiv = document.createElement("avdiv")
odiv.classList.add("s2-sav-menu","idExistent");
odiv.innerHTML = aPattern;
odiv.addEventListener("click",SearchPopupClick)
return odiv;
}
// 点击划词搜索
function SearchPopupClick(e) {
if(e.target.classList.contains("savsehuatang")){
// 防止多次点击导致重复发送请求
e.target.classList.remove("savsehuatang");
SearchSehuatang(e.target.dataset.avid);
}
var odiv = document.querySelector(".s2-sav-menu");
odiv.parentNode.removeChild(odiv);
}
// 获取色花堂的formhash
function Sehuatang_GetFormHash(){
let sehuatang_getTime = settings2.sehuatang_getTime;
let nowTime = new Date().getTime();
let sehuatangURL = `https://${window.location.host}`;
const debug = false;
// 不确定这个值会不会变动, 12小时获取一次
if(!sehuatang_getTime || nowTime-sehuatang_getTime > 43200000 || settings2.sehuatang_url != sehuatangURL){
GM_xmlhttpRequest({
method:"get",
url:sehuatangURL,
onload:function(data){
// console.log(data);
var parser=new DOMParser();
let htmlDoc=parser.parseFromString(data.responseText, "text/html");
let odom = htmlDoc.querySelector('input[name="formhash"]');
// console.log(odom);
let formhash_value = odom.value;
// console.log(formhash_value);
settings2.sehuatang_formhash = formhash_value;
settings2.sehuatang_getTime = nowTime;
settings2.sehuatang_url = sehuatangURL;
SaveSettings2();
}
})
if(debug){console.log(`重新获取色花堂的formhash`)};
}else{
if(debug){console.log(`没有重新获取色花堂的formhash`)}
}
}
// 色花堂搜索
function SearchSehuatang(avID){
let formhash = settings2.sehuatang_formhash;
let sehuatangURL = `https://${window.location.host}`;
if (formhash) {
GM_xmlhttpRequest({
method: "post",
url: sehuatangURL+"/search.php?mod=forum",
data: `formhash=${formhash}&srchtxt=${avID}&searchsubmit=yes`,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Origin":sehuatangURL,
"Referer":sehuatangURL
},
onload: function(data){
if(data.finalUrl){
window.open(data.finalUrl);
} else{
GM_setClipboard(avID)
window.open(`${sehuatangURL}/search.php`);
}
},
onerror : function(err){
console.log('SearchSehuatang error')
console.log(err)
}
});
} else {
GM_setClipboard(avID)
window.open(`${sehuatangURL}/search.php`);
}
}
// 保存设置
function SaveSettings2() {
GM_setValue("_98settings2", settings2);
}
// 创建元素
function ele(html) {
let temp = document.createElement('template');
html = html.trim();
temp.innerHTML = html;
return temp.content.firstChild;
}
})();